pascal递归算法noip竞赛材料.docx

上传人:b****8 文档编号:11210313 上传时间:2023-02-25 格式:DOCX 页数:29 大小:29.42KB
下载 相关 举报
pascal递归算法noip竞赛材料.docx_第1页
第1页 / 共29页
pascal递归算法noip竞赛材料.docx_第2页
第2页 / 共29页
pascal递归算法noip竞赛材料.docx_第3页
第3页 / 共29页
pascal递归算法noip竞赛材料.docx_第4页
第4页 / 共29页
pascal递归算法noip竞赛材料.docx_第5页
第5页 / 共29页
点击查看更多>>
下载资源
资源描述

pascal递归算法noip竞赛材料.docx

《pascal递归算法noip竞赛材料.docx》由会员分享,可在线阅读,更多相关《pascal递归算法noip竞赛材料.docx(29页珍藏版)》请在冰豆网上搜索。

pascal递归算法noip竞赛材料.docx

pascal递归算法noip竞赛材料

信息学竞赛―――递归算法

一个过程(或函数)直接或间接调用自己本身,这种过程(或函数)叫递归过程(或函数).递归程序包含递归和递推两个过程,这两个过程又都是根据一个递推公式进行的。

一般来说,能够用递归解决的问题应该满足以下三个条件

①需要解决的问题可以化为一个或多个子问题来求解,而这些子问题的求解方法与原来的问题完全相同,只是在数量规模上不同;

②递归调用的次数必须是有限的;

③必须有结束递归的条件(边界条件)来终止递归。

例1、楼梯共有N阶台阶,上楼可以以一步上一个台阶,也可以一步上二个台阶。

编一个程序计算上N阶台阶,共有多少种走法?

programstair(input,output);

vars,n:

integer;

functionf(n:

integer):

integer;

  begin  ifn<3thenf:

=n

               elsef:

=f(n-1)+f(n-2);

  end;

begin

   readln(n);

   s:

=f(n);

   writeln('s=',s);

end.

例2、骨牌铺法

有1*n的一个长方形,用一个1*1、1*2、1*3的骨牌铺满方格。

例如当n=3时为1*3的方格。

此时用1*1,1*2,1*3的骨牌铺满方格,共有四种铺法。

图4.4.3列出了四种铺法。

 

 

 

 

 

 

 

 

 

 

 

    

 

 

 

 

输入n(0<=n<=30)  输出 铺法总数

分析:

这道题可以采用猜测法,从具体的n=1,2,3,......开始,列举出结果,根据列举的部分结果进行猜测,推导出公式。

这个猜测推导过程留给读者完成。

问题是:

这种方法中“猜”和“凑”的成分比较多,容易出错。

我们不妨采用组合数学常用的待定系数进行归纳和推导。

设推导公式如下:

f(n)=a*f(n-1)+b*f(n-2)+c*f(n-3)+d*f(n-4)+....(a,b,c,d...是常系数)

即1*n的长方形的铺法由全部(a种)1*(n-1)的长方形铺法总数加上全部(b种)1*(n-2)的长方形的铺法总数加上全部(c种)1*(n-3)的长方形的铺法总数......注意排除重复情况。

(1)将n格分成1格和n-1格,计算f(n-1)的系数a。

右端1格的铺法有一种(a)。

显然,在一格中只有一种铺法,即f(n-1)的系数a=1。

 

 

 

 

 

(2)将n格分成2格和n-2格,计算f(n-2)的系数b。

右端2格的铺法有两种(b)。

由图可见,(b)的铺法包含在(a)的铺法中,而(c)的铺法不同于(a),因此f(n-2)的系数b=1。

 

(3)将n格分成3格和n-3格,计算f(n-3)的系数c。

右端3格的铺法有两种(图4.4.5)。

由图可见,(d)(e)(f)的铺法都可以归结到1格或2格中去,只有1*3的铺法(g)属于新的,因此f(n-3)的系数c=1。

将n格分成n-x格和x格(4<=x<=n-4)的情况都是重复的,因此不再讨论。

由此得出:

f

(1)=1,f

(2)=2,f(3)=4,

  

f(n)=f(n-1)+f(n-2)+f(n-3)  (n>=5)

程序:

varn:

integer;

functionf(i:

integer):

longint;

begin

 ifiin[1..2]

thenf:

=i

elseifi=3

thenf:

=4

elsef:

=f(I-1)+f(I-2)+f(I-3);

end;

begin

  readln(n);writeln(f(n));

end.

“铺砖问题”有推广价值。

例如某人走n级的楼梯,每步可以走1级、2级或3级,走完n级楼梯共有多少种走法。

这个问题的数学意义和解法与“铺砖问题”相同。

 

例3:

划分问题

 设s是一个具有n个元素的集合s={a1,a2,…an},现将s集合划分成k个满足下列条件的子集合s1,s2,s3。

    1、si<>空;

    2、si∩sj=空;

    3、s1∪s2∪s3….∪sn=s      (1<=i,j<=k,i<>j)

则称s1,s2…sn是集合s的一个划分,它相当于把集合s中的n个元素放入k个无标号的盒子中,使得没有一个盒子为空,试确定n个元素的集合放入k个无标号盒的划分数s(n,k)

【算法分析】:

   例如S={1,2,3,4},k=3。

细心的读者稍加分析后,不难得出S有6种不同的划分方案,即划分数为6。

其方案为{1,2}∪{3}∪{4}       {1,3}∪{2}∪{4}       {1,4}∪{2}∪{3}           {2,3}∪{1}∪{4}       {2,4}∪{1}∪{3}       {3,4}∪{1}∪{2}

   如果对于任意的S集合和k值,就不能凭籍直觉和经验计算划分数和枚举划分方案了。

必须总结出一个数学规律:

设n个元素a1…an放入k个无标号盒的划分数为S(n,k)。

在配置过程中,

 有两种情况:

1.设{an}是k个子集中的一个子集,于是把{a1…an-1}划分为k-1子集有S(n-1,k-1)个划分数;

2.如果{an}不是k个子集中的一个,即an必与其它的元素构成一个子集。

首先把{a1,…,an-1}划分成k个子集,这共有S(n-1,k)种划分方式。

然后 再把an加入到k个子集中的一个子集中去,这有k种加入方式。

对于每一种加入方式,都使集合划分为k个子集,因此由乘法原理知,划分数共有k·s(n-1,k)。

从上面的两种情况分析得出  S(n,k)=S(n-1,k-1)+k·S(n-1,k)            (n>1,k≥1)

下面,我们来确定s(n,k)的边界条件:

   1.我们不可能把n个元素不放进任何一个集合中去,即s(n,0)=0;也不可能在不允许空盒的情况下把n个元素放进多于n的k个集合中去,即k>n时S(n,k)=0。

   2.把n个元素放进一个集合或把n个元素放进n个集合,方式数显然是1。

                       S(n,1)=1

                       S(n,n)=1

显然,通过上述分析可得出划分数S(n,k)的递归关系式:

   S(n,k)=S(n-1,k-1)+k·S(n-1,k)     (n〉k,k≥1)                   

   S(n,k)=0                               (n

   S(n,k)=1                               (k=1)或(k=n)

按照划分数S(n,k)的递归定义,可以直接写出它的递归函数S(n,k)

   functionS(n,k:

integer)ofword;

   begin

     if(k=0)or(k>n)then  s:

=0

                    elseif(k=1)or(k=n)then s:

=1

                                       else s:

=s(n-1,k-1)+k*s(n-1,k);

   end;

 

相似题:

m个相同的球放进n个相同的盒子(可以一个盒子放多个)有多少种不同的放法?

       m个相同的球放进n个不相同的盒子(可以一个盒子放多个)有多少种不同的放法?

 

例4、简单的背包问题。

设有一个背包,可以放入的重量为s。

现有n件物品,重量分别为t1,t2,t3…ti…tn,ti(1≤i≤n),均为正整数。

从n件物品中挑选若干件,使得放入背包的重量之和正好为s

【输入样例】                            【输出样例】

thenumberofobject:

5                   number:

1weight:

1

totalweight=10                          number:

3weight:

2

16275                                number:

4weight:

7

【分析】尝试构造函数snap(s,n)解决本题,分析情况如下:

   ①、先取最后一个物品tn放入背包中,若tn=s,刚好放入包中,问题得到解决并输出(n,tn).

   ②、若tn>s,则不能放入包中,还得继续挑选;若还剩物品(即n>1),问题即为从剩余的n-1件物品中选取若干个,使得他们的重量和等于s,即snap(s,n)—>snap(s,n-1).

   ③、若tn1),那么问题即可转换为从剩下的n-1件物品中选取若干件,使得他们的重量和等于包里剩下的可放入重量(s-tn),即:

snap(s,n)—>snap(s,n-1);而选中的tn还要看snap(s-tn,n-1)是否有解,无解的话说明先取tn不合适,就要放弃tn,在剩余的物品中开始挑选,即有snap(s,n)—>snap(s,n-1).

【参考程序】

Constm=10;

vart:

array[1..m]ofinteger;

  x,y,i:

integer;f:

boolean;

functionsng(x:

integer):

integer;{判断s-t[n]的三种情况}

 begin  

    ifx>0thensng:

=1

                elseifx=0thensng:

=0

                            elsesng:

=-1;

 end;

functionsnap(s,n:

integer):

boolean;{判断是否有解}

 begin 

  casesng(s-t[n])of

    0:

beginwriteln(‘number:

’n:

4,‘weight:

’,t[n]:

4);snap:

=true;end;

    1:

beginifn>1thenifsnap(s-t[n],n-1)=truethen

                              beginwriteln(‘number:

’n:

4,‘weight:

’,t[n]:

4); snap:

=true;end

                             elsesnap:

=snap(s,n-1)

                    elsesnap:

=false

       end;

    -1:

ifn>1thensnap:

=snap(s,n-1)elsesnap:

=false

   end;

 end;

begin

  writeln(‘thenumberofobject:

’);readln(y);

  writeln(‘totalweight=’);readln(x);

  fori:

=1toydoread(t[i]);readln;{数据输入}

  f:

=snap(x,y); {x:

weight,y:

number}

  ifnot(f)thenwriteln(‘notfound’);

end.

例5、输出n个元素的无重复的全排列。

N个元素有n!

种不同排列。

分析:

1个元素直接输出;

2个元素有两种排列,如(ab)(ba);

3个元素以(abc)为例,有:

abc

acb

bac

bca

cba

cab

分析这些排列,一个简单的算法是:

(1)a后随(bc)的所有排列

(2)b后随(ac)的所有排列

(3)c后随(ba)的所有排列

上面

(2)是将

(1)中的a、b互换位置;上面(3)是将

(1)中的a、c互换位置。

这里意味着可以用循环的方法来重复执行“交换位置,后随剩余序列的所有的排列”;而对剩余序列可以再使用这个方法,这就成了递归调用,后随的元素没有时,就到了递归的边界。

对于n个元素a=(a1a2…ak…an),设过程prem(a,k,n)是求a的第k到n个元素的全排列,设swap(a,k,I)是将a的第k个元素和第i个元素对换,i=k,…,n。

programexp1_7;

vara:

string;k,n:

integer;

procedureswap(vara:

string;k,i:

integer);

vart:

char;

begin  t:

=a[k];a[k]:

=a[i];a[i]:

=t;

end;

procedureperm(a:

string;k,n:

integer);

vari:

integer;

begin

 ifk=nthenwriteln(a)

elsefori:

=ktondo begin swap(a,k,i);perm(a,k+1,n);    end

end;

begin

 readln(a);n:

=length(a);perm(a,1,n);

end.

 

例6、2的幂次方表示

任何一个正整数都可以用2的幂次方表示.例如:

137=2^7+2^3+2^0。

同时约定次方用括号来表示,即a^b可表示为a(b)。

由此可知,137可表示为:

2(7)+2(3)+2(0),进一步:

7=2^2+2+2^0 (2^1用2表示);3=2+2^0;所以最后137可表示为:

2(2

(2)+2+2(0))+2(2+2(0))+2(0)。

又如:

1315=2^10+2^8+2^5+2+1;所以1315最后可表示:

2(2(2+2(0))+2)+2(2(2+2(0)))+2(2

(2)+2(0))+2+2(0)

输入:

正整数(n≤20000)

输出:

符合约定的n的0,2表示(在表示中不能有空格)  

【分析】:

递归法

2的幂次方由高幂向低幂分解

1.         计算最接近n(小于n)的2的次幂e

 2e≤n<2e+1      设x=2e。

2.从e开始按照次幂递减的方向分解(0≤i≤e)设x1—项数。

若n≥x,则分解出x=2i的2幂次方表示:

⑴若x1>0(非第一项),则输出’+’;

⑵分析次幂i

i=0,输出2(0);                                             {递归边界}

i=1,输出2;

i>1,输出2(i的2幂次方表示)                                   {递归}

⑶准备分解下一项

x1←x1+1;n←n-x;

x←xdiv2;(无论n是否大于等于n)

由此得出算法:

proceduresolve(n:

word);

   var e,i,x1:

byte;

        x:

word;

begin

x←16384;e←14;                                                             {214<20000<215}

whilex>ndo                                                   {计算最接近n(小于n)的x=2e}

   begin x←xdiv2;e←e-1   end;{while}

 x1←0;

 fori←edownto0do                                 {逐位分解2的幂次i}

       begin

         ifn≥x thenbegin                                             {若能分解x=2i}

                           ifx1>0thenwrite(’+’);           {若当前是中间项}

                           caseiof                    {根据次幂i分解x的2幂次方表示}

                             0:

write(’2(0)’);

                             1:

write

(2);

                            elsebegin

                                    write(’2(’);

                                    solve(i);

                                    write(’)’)

                                 end{else}

                           end;{case}

                           x1←x1+1;n←n-x                      {准备分解下一项x=2i-1}

                       end;{then}

         x←xdiv2

       end{for}

end;{solve}

例7、求数字的乘积根。

一个正整数的数字的乘积N的定义是:

这个整数中非零数字的乘积。

例如,整数999的数字乘积为9*9*9,即729。

729的数字乘积为7*2*9,即126。

126的数字乘积为1*2*6,即12。

12的数字乘积为1*2,即2。

一个正整数的数字乘积根N是这样得到的:

反复取该整数的数字乘积,直到得到一位数字为止。

例如,在上面的例子中数字的乘积根是2。

编写一个程序,输入一个正整数(长度不超过200位数字),输出计算其数字乘积根的每一步结果。

【分析】:

每一步得到的乘积根比它的上一步的位数要小,显然存在递归过程,

递归结束的条件是乘积根的位数等于1。

具体程序编码如下:

programex5_17;

varst:

string;

procedureinit;

beginwriteln(‘pleaseinput:

’);readln(st);end;

proceduremake(ss:

string);

vara,b:

array[1..200]ofinteger;

i,j,x,code:

integer;w:

string;

begin

   fillchar(a,sizeof(a),0);

   fori:

=1tolength(ss)do      {取每一位数}

val(ss[i],a[i],code);

   fillchar(b,sizeof(b),0);

   x:

=1;b[1]:

=1;

   fori:

=1tolength(ss)do {每一位非0的数相乘}

     begin

forj:

=1toxdo

ifa[i]<>0thenb[j]:

=b[j]*a[i];

forj:

=1toxdo      {处理进位}

 begin  b[j+1]:

=b[j+1]+b[j]div10;

                 b[j]:

=b[j]mod10;

end;

ifb[x+1]>0thenx:

=x+1;

     end;

  ss:

=‘’;

  fori:

=xdownto1do

begin

  str(b[i],w);ss:

=ss+w;

end;

  writeln(ss);

  iflength(ss)>1thenmake(ss);

end;

begin

 init;{输入数据}

writeln(st);

make(st);{递归处理}

readln;

end.

 

例8、输入N个字符,然后以倒序输出(用递归实现)。

Programdigui(input,output);

Constn=8;

Typemat=array[1..n]ofchar;

Vari:

integer;a:

mat;

Procedureprint(i:

integer);

begin

  Ifi=nthenwrite(a[i])

         elsebeginprint(i+1);write(a[i]);end;

end;

Begin

 fori:

=1tondoreadln(a[i]);

 i:

=1;  print(i); readln;

End.

 

例9、猴子选大王:

有n只猴子选大王,先从头到尾1至3报数,报到3的猴子退出,报至尾后,再从尾到头1至3报数,报到3的猴子退出…依次类推,当剩下两只猴子时,报1的为大王。

问若想当大王,应站在什么位置。

【分析】:

十只猴子1-10编号,则出圈的次序为

猴子编号:

1 2 3 4 5 6 7 8 9 10

出圈次序:

3 6 9 7 2 5 4 10 剩下8和1时,8号猴子报1为大王

程序如下:

programhouzi(input,output);

typearr=array[1..100]ofinteger;

varh:

arr;I,j,m,n:

integer;

procedurenum(vara:

arr;varn,i:

integer;m:

integer);

var f,k,s:

integer;

begin

 ifn>=3then begins:

=0;k:

=imod2;{k为1表示从头到尾,k为0表示从尾到头}  

                      casekof

                          1:

forf:

=1tomdo {正向报数}

ifa[f]<>0then begin s:

=s+1;

                                                ifs=3thenbegins:

=0;n:

=n-1;a[f]:

=0;end;

end;

                          0:

forf:

=mdownto1do{反向报数}

ifa[f]<>0then  begin  s:

=s+1;

 ifs=3thenbegins:

=0;n:

=n-1;a[f]:

=0;end;

    end;

 end;

  i:

=i+1;num(a,n,i,m);{递归调用}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高等教育 > 哲学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1