作业选讲

55
09 09 信信信信信信信信 信信信信信信信信 作作作作 作作作作

Upload: ivy-michael

Post on 30-Dec-2015

36 views

Category:

Documents


5 download

DESCRIPTION

作业选讲. 给一维数组输入任意 6 个整数 , 假设为 : 7 4 8 9 1 5 请建立一个具有以下内容的方阵: 7 4 8 9 1 5 4 8 9 1 5 7 8 9 1 5 7 4 9 1 5 7 4 8 1 5 7 4 8 9 5 7 4 8 9 1 ( 请用子程序编写 ) 。. 赵自为. program zzw; const s :array[1..6] of integer=(1,2,3,4,5,6); var q:integer; procedure hhh ; var t,j:integer; - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 作业选讲

0909 信息奥赛暑假集训信息奥赛暑假集训

作业选讲作业选讲

Page 2: 作业选讲

给一维数组输入任意 6 个整数 , 假设为 :7 4 8 9 1 5请建立一个具有以下内容的方阵:7 4 8 9 1 54 8 9 1 5 78 9 1 5 7 49 1 5 7 4 8 1 5 7 4 8 95 7 4 8 9 1( 请用子程序编写 ) 。

Page 3: 作业选讲

program zzw;const s:array[1..6] of integer=(1,2,3,4,5,6);var q:integer;procedure hhh;var t,j:integer;begin

j:=s[1];for t:=1 to 5 do  s[t]:=s[t+1];s[6]:=j; for t:=1 to 6 do    write(s[t],' ');writeln;

end;Begin  for q:=1 to 6 do write(s[q],' ');   writeln;  for q:=1 to 5 do

  hhh;end.

赵自为

Page 4: 作业选讲

输入输入 nn 个正整数 求它们的最大公约数。。。个正整数 求它们的最大公约数。。。 (n=(n=5)5)program zzw;const n=5;var s:array[1..n] of integer; g,t:integer;function gys(x,y:integer):integer;var z:integer;begin repeat z:=x mod y; x:=y; y:=z; until z=0; gys:=x;end;begin for t:=1 to n do read(s[t]); g:=s[1]; for t:=2 to n do g:=gys(g,s[t]); writeln('the gys is ',g);end.

让程序更有通用性,

Page 5: 作业选讲

var m,nvar m,n :: longint longint ;;function function gcdgcd(m,n(m,n :: longint)longint) :: longintlongint ;;begin begin if if m mod n=0m mod n=0 then gcd :=n then gcd :=n else else gcd:=gcd(n, m mod n)gcd:=gcd(n, m mod n) ;;{递归调用}{递归调用}endend ;;begin begin { { 主程序 主程序 }} read (m,n)read (m,n) ;; writeln (‘m=’,m ,’n=’,n ,’gcd=’, writeln (‘m=’,m ,’n=’,n ,’gcd=’, gcd( m,n)gcd( m,n) ) ) ;;endend ..

Page 6: 作业选讲

0909 信息奥赛暑假集训信息奥赛暑假集训

递 归

第六次

Page 7: 作业选讲

我们把自己内部又有自己本身的这种情况叫做递归。

Page 8: 作业选讲

递 归 递 归

pascalpascal 语言中,如果在一个函数、过程等定义内部又语言中,如果在一个函数、过程等定义内部又直接或间接地出现有对自身的引用,则称它们是直接或间接地出现有对自身的引用,则称它们是递归递归的的或者是或者是递归定义递归定义的。的。

在程序中,递归是通过函数或过程的调用来实现的。在程序中,递归是通过函数或过程的调用来实现的。函数或过程直接调用其自身,称为函数或过程直接调用其自身,称为直接递归直接递归;函数或;函数或过程间接调用其自身,称为过程间接调用其自身,称为间接递归间接递归。。

Page 9: 作业选讲

procedure fac; begin . . . fac; . . .end;这种方式是直接调用 .

procedure b; procedure c;

begin begin

. .

.

. .

c; b;

. .

. .

end; end;

这种方式是间接调用 .

一个过程 ( 或函数 ) 直接或间接调用自己本身 , 这种过程( 或函数 ) 叫递归过程 ( 或函数 ).

Page 10: 作业选讲

如何设计递归算法

1. 确定递归公式

2. 确定边界 ( 终了 ) 条件

Page 11: 作业选讲

计算计算 n!n! 的函数的函数program hs_exam1;var i:integer;s :longint;  

begin

read(n);

s:=s+fac(n);

write(‘s=‘,s);

end.

function fac(n:integer):longint;    var k:integer; t:longint;    begin    t:=1; for k:=2 to n do t:=t*k; fac:=t; { 将计算结果值赋给函数,返回调用处 }   end;

Page 12: 作业选讲

例例 11 阶乘函数可递归地定义为:

0

0

)!1(

1!

n

n

nnn

边界条件

递归方程

边界条件与递归方程是递归函数的二个要素,递归函数只有具备了这两个要素,才能在有限次计算后得出结果。

Page 13: 作业选讲

program p1(input , output) ; var n:integer ; s:longint ; function fac(a : integer) : longint ; begin if a=0 then fac:=1 else fac:=a*fac(a-1) ; end ; begin readln(n) ; s:=fac(n) ; writeln(n ,‘ !=’ , s) end .

0

0

)!1(

1!

n

n

nnn

Page 14: 作业选讲

N!N! 可以由下列公式表示:可以由下列公式表示:

Page 15: 作业选讲
Page 16: 作业选讲

程序: program p1(input , output) ; var n : integer ; s : longint ; function fac(a : integer) : longint ; begin if a=0 then fac:=1 else fac:=a*fac(a-1) ; end ; begin readln(n) ; s:=fac(n) ; writeln(n ,‘ !=’ , s) end .

a=5 {fac(5)}

a=4 {fac(4)}

a=3 {fac(3)}

a=2 {fac(2)}

a=1 {fac(1)}

a=0 {fac(0)}

栈用于存放递归调用中不断产生的新的局部变量

a=0 {fac(0)}

a=1 {fac(1)}

a=2 {fac(2)}

a=3 {fac(3)}

a=4 {fac(4)}

a=5 {fac(5)}

11

2211

662424

120

Page 17: 作业选讲

在调用过程或函数之前,系统需完成三件事:在调用过程或函数之前,系统需完成三件事:⑴⑴ 为被调用过程的局部变量分配存储区;为被调用过程的局部变量分配存储区;⑵⑵ 将所有的实在参数、返回地址等信息传递给被调将所有的实在参数、返回地址等信息传递给被调

用过程保存;用过程保存;⑶⑶ 将控制转移到被调过程的入口。将控制转移到被调过程的入口。从被调用过程返回调用过程之前,系统也应完成三从被调用过程返回调用过程之前,系统也应完成三件工作:件工作:⑴⑴ 保存被调过程的计算结果;保存被调过程的计算结果;⑵⑵ 释放被调过程的数据区;释放被调过程的数据区;⑶⑶ 依照被调过程保存的返回地址将控制转移到调用依照被调过程保存的返回地址将控制转移到调用

过程。过程。

Page 18: 作业选讲

program p4(input , output) ;procedure rever ; var c : char ; begin read(c) ; if c<>'!' then rever; write(c) ; end ;begin { 主程序 } rever ;end .运行:输入 hey!输出 !yeh 。

程序中, c 是过程 rever 的局部变量。每一次递归调用,都要为局部变量重新分配单元,因此各层的变量 c实际上是不同的量,它们分别用于保存执行本层调用时的输入值。

例例输入一串以‘ !’ 结束的字符,按逆序输出。

Page 19: 作业选讲

procedure rever ; var c : char ; begin read(c) ; if c<>'!' then rever; write(c) ; end ;

hey!

c=‘h’procedure rever ; var c : char ; begin read(c) ; if c<>'!' then rever; write(c) ; end ;

procedure rever ; var c : char ; begin read(c) ; if c<>'!' then rever; write(c) ; end ;

procedure rever ; var c : char ; begin read(c) ; if c<>'!' then rever; write(c) ; end ;

c=‘e’

c=‘y’

c=‘!’

Page 20: 作业选讲

program exam_jc;

var n:integer;s:longint;

function fac(a:integer):longint;

begin

if a=0 then

fac:=1

else

fac:=a*fac(a-1);

end;

begin

readln(n);

s:=fac(n);

writeln(s)

end.

调试

Page 21: 作业选讲

program p4(input , output) ;procedure rever ; var c : char ; begin read(c) ; if c<>'!' then rever; write(c) ; end ;begin { 主程序 } rever ;end .运行:输入 hey!输出 !yeh 。

本例如果想输出为

Hey!!yeh

如何改

输入一串以‘ !’ 结束的字符,按逆序输出。

Page 22: 作业选讲

Procedrue begin 输出 n 的最右边的一个数字; if 还有数字 then 将余下的“数字倒序” end

例 4 :输入一个非负数,输出这个数的倒序数。

elseelse Procedrue reverse(n:integer); var nr,nl:integer; begin nr:=n mod 10; write(nr); nl:=n div 10; if nl<>0 then reverse(nl) end;

Page 23: 作业选讲

递归过程分析—数字倒序递归过程分析—数字倒序

Page 24: 作业选讲

例 3 、用递归方法求两个正整数用递归方法求两个正整数 mm 和和 nn 的最大公约数。的最大公约数。

分析:求两个数的最大公约数可以用求两个数的最大公约数可以用辗转相除辗转相除法法,即求,即求 mm 与与 nn 的最大公约数等价于求(的最大公约数等价于求( m mm mod nod n )的值与)的值与 nn 的最大公约数,此时的的最大公约数,此时的 nn 可以可以当作新的当作新的 m m ,而(,而( m mod nm mod n )的值当作新的)的值当作新的 n n ,所以原问题的求解又变成求新的,所以原问题的求解又变成求新的 mm 与与 nn 的最的最大公约数问题,继续下去,直至大公约数问题,继续下去,直至 (m mod n)(m mod n) 为为 00 ,,最大公约数就是最终存放在最大公约数就是最终存放在 nn 中的值。中的值。

6 2 0

Page 25: 作业选讲

function gys(x,y:integer):integer;

  var z:integer;

  begin

  repeat

   z:=x mod y; x:=y; y:=z;

  until z=0;

gys:=x;

end;

Page 26: 作业选讲

var m,nvar m,n :: longint longint ;;function gcd(m,nfunction gcd(m,n :: longint)longint) :: longintlongint ;;begin begin if if m mod n=0m mod n=0 then gcd :=n then gcd :=n else else gcd:=gcd(n, m mod n)gcd:=gcd(n, m mod n) ;;{递归调用}{递归调用}endend ;;begin begin { { 主程序 主程序 }} read (m,n)read (m,n) ;; writeln (‘m=’,m ,’n=’,n ,’gcd=’, gcd( m,n) )writeln (‘m=’,m ,’n=’,n ,’gcd=’, gcd( m,n) ) ;;endend ..

递归公式:递归公式:

Page 27: 作业选讲

例例 5:5: 用递归算法把任一给定的十进制正整数( <=32000 )转换成八进制数输出。

分析:利用短除法不断除以 8取余数这个重复过程,将原数据不断缩小,形成递归关系,当数据规模缩小至 0时,递归结束。

procedure tran(n:longint); { 递归过程 } var k:longint; begin k:=n mod 8; { 取除以 8 以后的余数 } n:=n div 8; { 取除以 8 以后的商 } if n<>0 then tran(n); { 直到商为 0 ,结束递归过程 } write(k:1) end;

Page 28: 作业选讲

会当凌绝顶,一览众山小

Page 29: 作业选讲

1 . var i,a,b,c,d:integer; f:array[0..3] of integer; begin for i:=0 to 3 do read(f[i]); a:=f[0]+f[1]+f[2]+f[3]; a:=a div f[0]; b:=f[0]+f[2]+f[3]; c:=(b*f[1]+a) div f[2]; d:=f[(b div c) mod 4]; if (f[(a+b+c+d) mod 4]>f[2]) then begin a:=a+b; writeln(a) end else begin c:=c+d; writeln(c);end; end.

输入: 9 19 29 39

Page 30: 作业选讲

2 . procedure foo(a,b,c:integer); begin if a>b then foo(c,a,b) else writeln(a,',',b,',',c) end; var a,b,c:integer; begin readln(a,b,c); foo(a,b,c); end.

输入: 2 1 3输出: _________________

1 3 2

Page 31: 作业选讲

3 . procedure f(a,b,c:integer); begin write(a,b,c,'/'); If (a=3)and(b=2)and(c=1) then exit; if (b<c) then f(a,c,b) else if a<b then if a<c then f(c,a,b) else f(b,c,a); end; var a,b,c:integer; begin readln(a,b,c); f(a,b,c); end.

输入: 1 3 2

Page 32: 作业选讲

var s:string; i,j,len,k:integer;begin readln(s);len:=length(s);for i:=1 to len do if (ord(s[i])>=ord('A')) and (ord(s[i])<=ord('Z')) then s:=chr(ord(s[i])-ord('A')+ord('a'));for i:=1 to len doif (ord(s[i])<ord('X')) then s:=chr(ord(s[i])+3) else s:=chr(ord(s[i])-23);write(s); write('/');for j:=1 to 3 do begin i:=1; while i<=len-j do begin s[i]:=s[i+j];i:=i+j; end; end;writeln(s);end. 输入: ABCDEFGuvwxyz

Page 33: 作业选讲

以上是 2008提高组初赛读程序题

32 分

Page 34: 作业选讲

例例 55 、用递归算法完成折半查找。、用递归算法完成折半查找。

分析:折半查找是在一列升序或降序的数中查找目标数。设数放置在数分析:折半查找是在一列升序或降序的数中查找目标数。设数放置在数

组组 aa 中,中, toptop 、、 midmid 、、 botbot 分别作为低、中、高指针,若需要查找的数是分别作为低、中、高指针,若需要查找的数是

xx ,可以完成以下三种比较:,可以完成以下三种比较:

(( 11 ) 若) 若 x=a[mid]x=a[mid] ,则表示找到。,则表示找到。

(( 22 ) 若) 若 x<a[mid]x<a[mid] ,则进行下一步查找,,则进行下一步查找, toptop 不变,不变, botbot 变成变成 mid-1mid-1 。。

(( 33 ) 若) 若 x>a[mid]x>a[mid] ,则进行下一步查找,,则进行下一步查找, toptop 变成变成 mid+1mid+1 ,, botbot 不变。不变。

显然,(显然,( 22 )、()、( 33 )出现了递归关系,数据规模在不断缩小,递归结)出现了递归关系,数据规模在不断缩小,递归结

束的条件有两个,要么找到,既束的条件有两个,要么找到,既 x=a[mid]x=a[mid] ;要么找不到,即出现;要么找不到,即出现 top>bottop>bot

1   5   11   15   19   26 37   48   59 61

toptop botbotmidmid

15

Page 35: 作业选讲

function search(top,bot:integer):Integer;function search(top,bot:integer):Integer; var mid: integer;var mid: integer;begin begin if top>bot then search:=-1if top>bot then search:=-1 else else begin begin mid:=(top+bot) div 2;mid:=(top+bot) div 2; if if x=a[mid]x=a[mid] then begin search:=mid; exit;end; then begin search:=mid; exit;end; else else

if x<a[mid] then search:= if x<a[mid] then search:=search(top,mid-1)search(top,mid-1) else search:=else search:=search(mid+1,bot)search(mid+1,bot) endendend;end;

Page 36: 作业选讲

思考:思考: 00 ,, 11 ,, 11 ,, 22 ,, 33 ,, 55 ,, 88 ,, 1313 ,, 2121 ,, 3434 ,, 55……55…… 从第三项起,每从第三项起,每一项都是紧挨着的前两项的和。写出计算斐波那切数列的任意一个数据项一项都是紧挨着的前两项的和。写出计算斐波那切数列的任意一个数据项递归函数形式。 递归函数形式。

function fic(mfunction fic(m :: integer)integer) :: longlongintint ;; begin begin

if if m=1m=1 then fic:=0 then fic:=0

if if m=2m=2 then fic:=1 then fic:=1

ifif m>2m>2 then then fic:=fic(m-1)+fic(m-2fic:=fic(m-1)+fic(m-2 ) ) {递归调用}{递归调用} endend ;;

Page 37: 作业选讲

procedure p (n:integer);var i:integer;begin

if n>0 then begin

    for i:=1 to n do write(n:3);    writeln;

      p(n-1);    for i:=1 to n do write(n:3);    writeln;   end;

end; 执行 P(4)

for i:=1 to n do write(3:3);writeln;p(2);for i:=1 to n do write(n:3);writeln;

n=3

for i:=1 to 2 do write(2:3);writeln;p(1);for i:=1 to n do write(n:3);writeln;

n=2

for i:=1 to 1 do write(1:3);writeln;p(0);for i:=1 to n do write(n:3);writeln;

n=1

n=4

for i:=1 to 4 do write(4:3); writeln; p(3); for i:=1 to 4 do write(n:3);writeln;

n=0 为边界条件不再展开

for i:=1 to 1 do write(1:3);writeln;p(0);for i:=1 to n do write(n:3);writeln;

n=0

Page 38: 作业选讲

program ex404;var x,x2:longint;procedure digit(n,m:longint);var n2:integer;begin if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end;end; begin writeln('Input a number:'); readln(x); x2:=1; while(x2<x) do x2:=x2*10; x2:=x2 div 10; digit(x,x2); writeln; end.

第十二届全国青少年信息学奥林匹克联赛初赛试题

输入: 9734526

9734526 10000000

x x2

8位7位

1000000

7位

n m

n2=n mod 10

7次

6次

Page 39: 作业选讲

if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end;

9734526

n

n2=n mod 10 1000000

m

973452

if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end;

if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end;

if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end;

if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end;

if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end;

if(m>0) then begin n2:=n mod 10; write(n2:2); if(m>1) then digit(n div 10,m div 10); n2:=n mod 10; write(n2:2); end;

97345 9734

973 97 9

100000 10000 1000

100 10 1

6 2

9734526

5 4 3 7 9 9 7 3 4 5 2 6

973452 97345

9734 973 97

9

n

第二个 if 语句后的 n ,是调用是的 n ,值参数据传递是单向的,数据不回带

Page 40: 作业选讲

递归要素:完成递归必须考虑的因素有两个。 递归要素:完成递归必须考虑的因素有两个。 (( 11 )边界条件。也就是所描述问题的最简单情况,它本)边界条件。也就是所描述问题的最简单情况,它本身不再使用递归的定义。如阶乘,当身不再使用递归的定义。如阶乘,当 n=0n=0 时,时, f(n)=1f(n)=1 ,不,不使用使用 f(n-1)f(n-1) 来定义。 来定义。 (( 22 )递归关系。使问题向边界条件转化的规则。递归)递归关系。使问题向边界条件转化的规则。递归定义必须能使问题的规模越来越简单。 定义必须能使问题的规模越来越简单。

递归的优点:长处是,它能使一个蕴含递归关系且结构复杂的递归的优点:长处是,它能使一个蕴含递归关系且结构复杂的程序简介精炼,增加可读性。 特别是在难于找到从边界到解的全过程序简介精炼,增加可读性。 特别是在难于找到从边界到解的全过程的情况下,如果把问题推进一步程的情况下,如果把问题推进一步 ,, 其结果仍维持原问题的关系,其结果仍维持原问题的关系,则采用递归算法编程比较合适。递归的缺点:递归算法的效率往往则采用递归算法编程比较合适。递归的缺点:递归算法的效率往往很低,费时和费内存空间。很低,费时和费内存空间。

Page 41: 作业选讲

快速排序

[ 分析 ] 基本思想

  快速排序的思想是 :先从数据序列中选一个元素 ,并将序列中所有比该元素小的元素都放到它的右边或左边 ,再对左右两边分别用同样的方法处之直到每一个待处理的序列的长度为 1, 处理结束 设 N 个元素 A[1..N] ,要求按非递减排序。 选择某一个元素 X (一般取中间那个,初始时设 i=1,j=N, 则 X

=a[ ( i+j) div 2] ),从两头 (A[i] 、 A[j])开始逐个与 X比较,找到左边比它大的那个元素 A[i] 和右边比它小的那个元素 A[j] ,则交换 A[i] 与 A[j] ,一举两得,然后 inc(i) 、 dec(j)再继续进行,直到 i>j 。则这一趟结束,效果是 X 一定排在了它应该在的位置上了。

Page 42: 作业选讲

A 3 1 9 8 4 7 5 2 0 6

1 2 3 4 5 6 7 8 9 10

A 3 1 0 2 4 7 5 8 9 6

1 2 3 4 5 6 7 8 9 10

i jMid

X

然后,对 X左右两边的部分进行类似的递归操作。实际上是一种二分思想,即把大于某个数的所有数交换到它的右边,而把小于它的数都交换到左边。如此这般递归下去,直到都符合要求为止。

Page 43: 作业选讲

例 3 、快速排序

[ 分析 ]基本思想  快速排序的思想是 :先从数据序列中选一个元素 ,并将序列中所有比该元素小的元素都放到它的右边或左边 ,再对左右两边分别用同样的方法处之直到每一个待处理的序列的长度为 1, 处理结束 .

[编辑本段 ] 算法过程  设要排序的数组是 A[0]……A[N-1] ,首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一躺快速排序。一躺快速排序的算法是:   1 )设置两个变量 I 、 J ,排序开始的时候: I=1 , J=N ;   2 )以第一个数组元素作为关键数据,赋值给 X ,即 X=A[1] ;   3 )从 J开始向前搜索,即由后开始向前搜索( J=J-1 ),找到第一个小于 X

的值,让该值与 X交换;   4 )从 I开始向后搜索,即由前开始向后搜索( I=I+1 ),找到第一个大于 X

的值,让该值与 X交换;   5 )重复第 3 、 4步,直到 I=J ;  

Page 44: 作业选讲

program kspv;const n=7;Type arr=array[1..n] of integer;Var a:arr; i:integer;procedure sort(l,r:integer); var i,j,mid,t1:integer; begin i:=l;j:=r; mid:=a[(l+r) div 2]; { 将当前序列在中间位置的数定义为中间数 } repeat while a[i]< mid do inc(i); { 在左半部分寻找比中间数大的数 } while mid< a[j] do dec(j); { 在右半部分寻找比中间数小的数 } if i< =j then begin {若找到一组与排序目标不一致的数对则交换它们 } t1:=a[j];a[j]:=a[i];a[i]:=t1; inc(i);dec(j); { 继续找 } end; until i >j; if l< j then sort(l,j); {若未到两个数的边界,则递归搜索左右区间 } if i< r then sort(i,r); end;{sort}

[35 28 46 17 15]

i j

begin

write('input data:');

for i:=1 to n do read(a[i]);

writeln;

sort(1,n);

write('output data:');

for i:=1 to n do write(a[i]:6);

writeln;

end.

以中间元素为作为基准

Page 45: 作业选讲

由 m 个 A , n 个 B组成若干个排列。从某个排列的位置1开始数,数到任意位置时都能保证 A 的个数不少于 B的个数,则称该排列为合理排列。

例如:当 m=2 , n=2 时排列有 A A B B(合理 ) A B A B(合理 )A B B A( 不合理 ) B B A A( 不合理 ) 合理排列数有 2 种

输入:只有一行两个整数 m,n ( 1≤n≤m≤12 )(用 空格分隔)输出:一个整数(所有的合理排列数)【样例】输入 输出 3 2 5

开阔视野

Page 46: 作业选讲

分析:模拟排队的情况,从第分析:模拟排队的情况,从第 11 个人开始,第个人开始,第 1 1 人只能人只能是是 AA ,第,第 22 个可以是个可以是 AA 也可以是也可以是 BB ,再其后的人要保证,再其后的人要保证任意位置时都能保证任意位置时都能保证 AA 的个数不少于的个数不少于 BB 的个数,递归生的个数,递归生成整个排列。成整个排列。

Var m,n,t:LongInt;Procedure pd(i,j:LongInt);Begin If (i=m) And (j=n) Then t:=t+1{ 已生成一种排列 } Else Begin If i<m Then pd(i+1,j);{ 增加 1 个 A} If (j<n) And (j<i) Then pd(i,j+1); End; { 增加 1 个 B}End;Begin t:=0; Read(m,n);pd(1,0);Writeln(t);End.

Page 47: 作业选讲

汉诺塔(汉诺塔( tower of Hanoitower of Hanoi )问题。有)问题。有 nn 个大小不等个大小不等的中空圆盘,按照从小到大的顺序迭套在立柱的中空圆盘,按照从小到大的顺序迭套在立柱 AA 上,上,另有两根立柱另有两根立柱 BB 和和 CC 。现要求把全部圆盘从。现要求把全部圆盘从 AA 柱柱(源柱)移到(源柱)移到 CC柱(目标柱),移动过程中可借助柱(目标柱),移动过程中可借助BB柱(中间柱)。移动时有如下的要求:柱(中间柱)。移动时有如下的要求:①①一次只移动一个盘;一次只移动一个盘;②②不允许把大盘放在小盘上边;不允许把大盘放在小盘上边;③③可使用任意一根立柱暂存圆盘。可使用任意一根立柱暂存圆盘。

Page 48: 作业选讲

先以三个盘的移动为例,看一下移动过程。先以三个盘的移动为例,看一下移动过程。

Page 49: 作业选讲

分析:首先将分析:首先将 AA 柱上方的柱上方的 n-1n-1 个盘子从个盘子从 AA 柱移到柱移到 BB柱,此过程中柱,此过程中 CC 柱为中间柱;接着将柱为中间柱;接着将 AA 柱剩下的一柱剩下的一个盘子移到个盘子移到 CC 柱;最后再将柱;最后再将 BB 柱上的柱上的 n-1n-1 个盘子移个盘子移到到 CC 柱,此过程中柱,此过程中 AA 柱柱为为中间柱,这就变成了移动中间柱,这就变成了移动n-1n-1 个盘子的问题了。定义过程个盘子的问题了。定义过程 hanoihanoi ,实现这一递,实现这一递归算法:归算法: 若若 n=1n=1 ,则,则 A→CA→C 若若 n>=2n>=2 ,则   ,则    hanoi(n-1hanoi(n-1 ,, AA ,, CC ,, B) B)             A→CA→C             hanoi(n-1hanoi(n-1 ,, BB ,, AA ,, C) C)

运行结果:运行结果: Enter the number of disks in Hanoi towerEnter the number of disks in Hanoi tower :: 33A→CA→CA→BA→BC→BC→BA→CA→CB→AB→AB→CB→CA→CA→C

Page 50: 作业选讲

语句:语句: Hanoi(3Hanoi(3,‘,‘ A’A’,‘,‘ B’B’,‘,‘ C’)C’)

在执行过程中,递归工作栈要为每一层的递归保在执行过程中,递归工作栈要为每一层的递归保留数据,由于递归过程留数据,由于递归过程 hanoihanoi 只含有四个值参数,只含有四个值参数,也无其它局部变量,因而每一层递归需记录五个也无其它局部变量,因而每一层递归需记录五个数据项:返回地址和四个值参。 数据项:返回地址和四个值参。 (( 栈中内容为返栈中内容为返回的程序行号,参数回的程序行号,参数 nn ,参数,参数 xx ,参数,参数 yy ,参数,参数z)z)

Page 51: 作业选讲

var nvar n :: integerinteger ;;procedure hanoi(n:integer;x,y,zprocedure hanoi(n:integer;x,y,z :: char)char) ;;beginbegin    if n=1 then writeln(x, ‘->’,n, ‘->’,z)if n=1 then writeln(x, ‘->’,n, ‘->’,z)    else beginelse begin        hanoi(n-1,x,z,y)hanoi(n-1,x,z,y) ;;        writeln(x, ‘->’,n, ‘->’,z)writeln(x, ‘->’,n, ‘->’,z) ;;        hanoi(n-1,y,x,z)hanoi(n-1,y,x,z) endendendend ;;begin begin       {{ 主程序)主程序) readln(n)readln(n) ;; hanoi(n,‘A’,‘B’,‘C’)hanoi(n,‘A’,‘B’,‘C’)endend . .

Page 52: 作业选讲

把自然数N( N<= 100 )分解为若干个自然数之和,有几种情况。

如 N= 5 时,有 7 种情况

5=1+1+1+1+1

5=1+1+1+2

5=1+1+3

5=1+2+2

5=1+4

5=2+3

5=5

开阔视野

Page 53: 作业选讲

5

1 2 3 4 5

1 2 3 4 1 2 3

1 2 3

1 2

1

1

1 2 1 1

1 2 1

procedure find(n,i:integer);var j,k:integer;begin for j:=1 to n do if (j>=a[i-1]) then begin a[i]:=j; if n=j then begin for k:=1 to i-1 do write(a[k],'+'); write(a[i]); writeln; t:=t+1 ; end else find(n-j,i+1); writeln('*') end;

Page 54: 作业选讲

var a:array[0..100] of integer; n,t:integer;procedure find(n,i:integer);var j,k:integer;begin for j:=1 to n do if (j>=a[i-1]) then begin a[i]:=j; if n=j then begin for k:=1 to i-1 do write(a[k],'+'); write(a[i]); writeln; t:=t+1 ; end else find(n-j,i+1); writeln('*') end;end;begin read(n); t:=0; a[0]:=0; find(n,1); writeln(t);end.

Page 55: 作业选讲

var path :array[1..1000] of integer; total,n:integer; procedure find(k,sum,dep:integer); {K:} var b,d:Integer; begin if sum=n then { 积等于 N} begin write(n,'=',path[1]); for d:=2 to dep-1 do write('*',path[d]); writeln;inc(total); exit; end; if sum>n then exit; { 累积大于 N} for b:= trunc(n/sum)+1 downto k do { 每一种可能都去试 } begin path[dep]:=b; find(b,sum*b,dep+1); end; end; begin readln(n); total:=0; find(2,1,1);writeln('total:',total); readln; end.

把自然数N分解为若干个自然数之积。 N=6

K(b) sum dep

2 1 1

24

2 3 4 |6 8 12