7.递推讲解

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

7.递推讲解
七、递推
所谓递推,是指从已知的初始条件出发,依据某种递推关系,逐次推出所要求的各中间结果及最后结果。

其中初始条件或是问题本⾝已经给定,或是通过对问题的分析与化简后确定。

可⽤递推算法求解的题⽬⼀般有以下⼆个特点:
(1)问题可以划分成多个状态;
(2)除初始状态外,其它各个状态都可以⽤固定的递推关系式来表⽰。

在我们实际解题中,题⽬不会直接给出递推关系式,⽽是需要通过分析各种状态,找出递推关系式。

⼀、采⽤具体化、特殊化的⽅法寻找规律
例、平⾯上n条直线,任两条不平⾏,任三条不共点,问这n条直线把这平⾯划分为多少个部分?
设这n条直线把这平⾯划分成Fn个部分。

先⽤具体化特殊化的⽅法寻找规律,如图所⽰,易知的前⼏项分别为
F1=2,F2=4,F3=7,F4=11……这些数字之间的规律性不很明显,较难⽤不完全归纳法猜出Fn的⼀般表达式。

但我们可以分析前后项之间的递推关系,因为这些图形中,后⼀个都是由前⼀个添加⼀条直线⽽得到的,添加⼀条直线便增加若⼲个区域。

设原来的符合题意的n-1条直线把这平⾯分成个区域,再增加⼀条直线l,就变成n条直线,按题设条件,这l必须与原有的n-1条直线各有⼀个交点, 且这n-1个交点及原有的交点互不重合。

这n-1个交点把l划分成n个区间,每个区间把所在的原来区域⼀分为⼆,所以就相应⽐原来另增了n个区域,即:
F n =F
n-1
+_______(n=2,3……)这样,我们就找到了⼀个从F n-1到F n的的递推式,再加上已知的初始值F1=2,就可
以通过n-1步可重复的简单运算推导出F n的值。

var a,i,n:longint;
begin
read(n);
a:=2;
for i:=2 to n do
a:=a+i;
writeln(a);
end.
例、平⾯上有8个圆,最多能把平⾯分成⼏部分?
Fn=Fn-1+2× (n-1)
例、如图1,是棱长为a的⼩正⽅体,图2,图3由这样的⼩正⽅体摆放⽽成。

按照这样的⽅法继续摆放,⾃上⽽下分别叫第⼀层、第⼆层、……、第n层,第n层的⼩正⽅体的个数记为sn。

请写出求sn的递推公式。

1 3 6 10
S n=___________
例、如图,有边长为1的等边三⾓形卡⽚若⼲张,使⽤这些三⾓形卡⽚拼出边长分别是2,3,4,…的等边三⾓形(如图所
⽰).根据图形推断,写出求每个等边三⾓形所⽤卡⽚总数sn的递推公式.
4 9 16 2
5 36
S2=4 s n=s n-1+2*n-1 (n>2)
例、将⼀张长⽅形的纸对折,可得到⼀条折痕,继续对折,对折时每次折痕与上次的折痕保持平⾏,连续对折三次后,可得到7条折痕,那么对折n次,可得到⼏条折痕?(F n=2*F n-1+1)
例、如图,第⼀次把三⾓形剪去⼀个⾓后,图中最多有四个⾓,第⼆次再把新产⽣的⾓各剪⼀⼑,…,如此下去, 每⼀次都是把新产⽣的⾓各剪⼀⼑,则第n次剪好后,图中最多有多少个⾓?
4 6 10 18 34
F n=F n-1+_______
例、如图,由等圆组成的⼀组图中,第个图由个圆组成,第个图由个圆组成,第个图由个圆组成,……,按照这样的规律排列下去,则第9个图形由__________个圆组成。

可得递推公式:F n = F n-1+___________
例、下图中把⼤正⽅形各边平均分成了5份,此时有55个正⽅形。

如果把正⽅形各边平均分成n 份,那么得到
52+42+32+22+12=55 n 2+(n-1)2+(n-2)2+…+22+1 F n =F n-1+______
Var
a:array[1..25] of longint;
i,j,k,x,n:longint;
begin
readln(n);
a[25]:=1;{n=1时}
for i:= 2 to n do
begin
x:=i*i;
for j:= 25 downto 1 do
begin
a[j]:=a[j]+x mod 10;
if a[j]>=10 then
begin
a[j]:=a[j]-10 ; a[j-1]:=a[j-1]+1;
end;
x:=x div 10;
end;
end;
j:=1;
while a[j]=0 do j:=j+1;
for i:= j to 25 do write(a[i]);
end.
例、将n个不同颜⾊的球放⼊k个⽆标号的盒⼦中(n≥k,且盒⼦不允许为空)的⽅案数为S( n,k),例如:n=4, k=3时,S(
n,k)=6
当n=6,k=3时,S(n,k)=()。

分析:分两种情况,(1)第n个球单独成堆,此时有S(n-1,k-1)种放法。

(2)第n个球不单独成堆,⽽是和其它球合成⼀堆,此时将先前的(n-1)个球分成k堆,然后将第n个球插⼊某⼀堆中,对于前(n-1)个球分成k堆的⽅案,都有k种插法,所以此时的k*s(n-1,k)种⽅案,综上所述,s(n,k)的递推式为:s(1,1)=1
s(n,k)=0 (当n
s(n,k)= (n>=k时)
例:汉诺塔问题
分析:设h n为n个盘⼦从A柱移到C柱移动的次数。

显然,当n=1时,只需要把A柱上的盘⼦直接移到C 柱上就可以了,故:
h1=1。

当n=2时, h2=3。

依此类推,当A上有n(n>=2)个盘⼦时,总是先借助C柱把上⾯的n-1个盘⼦移到B柱上,这时须移动的次数为h n-1次,再把A柱上最后⼀个移到C上。

再借助A柱把B 柱上的n-1个盘⼦移到C上,这时⼜必须移动h n-1次。

故共移动________________次,所以:
h n =___h n-1+___,其中边界条件为:h1=1。

例、hanoi双塔问题给定A、B、C三根⾜够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n 个不同的尺⼨,每个尺⼨都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为n=3的情形)。

现要将这些圆盘移到C柱上,在移动过程中可放在B柱上暂存。

要求:(1)每次只能移动⼀个圆盘;(2)A、B、C三根细柱上的圆盘都要保持上⼩下⼤的顺序;任务:设An 为2n个圆盘完成上述任务所需的最少移动次数,对于输⼊的n,输出An。

输⼊⽂件hanoi.in为⼀个正整数n,表⽰在A柱上放有2n个圆盘。

输出⽂件hanoi.out仅⼀⾏,包含⼀个正整数,为完成上述任务所需的最少移动次数An。

【限制】对于50%的数据,1<=n<=25 对于100%的数据,1<=n<=200
【提⽰】设法建⽴An与An-1的递推关系式。

2 6 14 30 62 126 254…: An=An-1+______
解题思路: 递推+⾼精度
1. 假设当前要移动A轴的N层,即2N个盘⼦,则需要将N-1层的2N-2个盘⼦移动到B轴(辅助轴)上,再将第N层的2个盘⼦移动到C轴上(⽬标轴),然后再将那N-1层的2N-2个盘⼦移动到⽬标轴,共需要2*An-1+2次。

2. 递推关系式是: An=2*An-1+2
A0=0
var
a:array[1..62]of integer;{存放⼤数}
i,j,n:integer;
f:boolean;
begin
assign(input,'hanoi.in'); assign(output,'hanoi.out');
reset(input); rewrite(output);
readln(n);{层数}
for i:=1 to 62 do a[i]:=0;{初值}
for i:=1 to n do {递推n次}
begin
for j:=1 to 62 do a[j]:=a[j]*2; {先乘2}
a[1]:=a[1]+2; {再在个位上加2}
for j:=1 to 62 do
if a[j]>9 then begin {处理进位}
a[j+1]:=a[j+1]+1; a[j]:=a[j] mod 10;
end;
end;
f:=false;
for i:=62 downto 1 do
begin
if a[i]<>0 then f:=true;
if f then write(a[i]);
end;
close(input); close(output);
end.
例、平⾯分割问题:设有n 条封闭曲线画在平⾯上,⽽任何两条封闭曲线相交于两点,且任何三条封闭曲线不相交于⼀点,求这些封闭曲线把平⾯分割区域的个数。

分析:设a n 为n 条曲线把平⾯分成的区域数,由上图可以看出,a2-a1=2,a3-a2=4,a4-a3=6。

从这些式⼦可以看出,a n -a n-1=2(n-1),证明⼀下:当平⾯已有n-1条曲线将平⾯分割成a n-1个区域后,第n 条曲线每与其它曲线相交⼀次就会增加⼀个区域,第n 条与其它的n-1条共有_________交点,增加第n 条曲线后共增加区域___________个,所以,本题的递推关系式为:a n=a n-1+_
⼆、通过合理分步、恰当分类找出递推关系例、楼梯共有N 阶台阶,上楼可以以⼀步上⼀个台阶,也可以⼀步上两个台阶。

计算上N 阶台阶共有多少种⾛法。

分析:最终⽬标是到达N 阶,逆向分析,到达N 阶的前⼀步在哪⾥?只能是在N-1或N-2阶上。

即已得到了具有直接联系的两种状态,下⾯找出它们之间的关系表达式。

设上N-1阶共有F (N-1)种⾛法,上N-2阶有F (N-2)种⾛法,则上N 阶有F (N )种⾛法,假设你已经到达N-1阶,现在你有多少种⾛法到达N 阶呢?当然只有⼀种,即跨⼀步就到了N 阶。

因此,通过N-1阶到达N 阶的⾛法有F (N-1)种⾛法。

再假设你已经到达N-2阶,从这⾥到N 阶有多少种⾛法?有⼆种,⼀种是先到第N-1阶,再到第N 阶,另⼀种是直接跨2阶到达N 阶。

第⼀种⾛法实际已包含在先到N-1阶,再到N 阶的⾛中,所以不⽤计算,否则就重复了。

从N-2直接跨到N 阶有F (N-2)种,综上所述,到达N 阶的⾛法有:F (N )= ____________+______________。

编程:n 级台阶可以⼀步上、⼆步上、三步上的⾛法。

例、过河卒 [问题描述]:如图,A 点有⼀个过河卒,需要⾛到⽬标 B 点。

卒⾏⾛规则:可以向下、或者向右。

同时在棋盘上的
任⼀点有⼀个对⽅的马(如图的C 点),该马所在的点和所有跳跃⼀步可达的点称为对⽅马的控制点。

如图 C 点上的马可以控制 9 个点(图中的P1,P2…… P8 和 C )。

卒不能通过对⽅马的控制点。

棋盘⽤坐标表⽰,A 点(0,0)、B 点(n ,m )(n ,m 为不超过20的整数,并由键盘输⼊),同样马的位置坐标是需要给出的(约定:C ≠A ,同时C ≠B )。

现在要求你计算出卒从A 点能够到达B 点的路径的条数。

输⼊:键盘输⼊B 点的坐标(n ,m )以及对⽅马的坐标(X ,Y )输出:屏幕输出⼀个整数(路径的条数)。

输⼊输出样例:输⼊:3 3 2 2 输出:0
n=1 n=2
n=3 n=4
1、计算对⽅马的控制点:按照题意,对⽅的马所在的点和所有跳跃⼀步可达的点称为对⽅马的控制点,卒不能通过对⽅马的控制点。

在卒出发之前,必须计算对⽅马的所有控制点。

显然,若(0,0)或(n,m)为控制点,则输出路径数为0。


c o n s t
m o v e:a r r a y[1..8,1..2]o f i n t e g e r=((1,-2),(1,2),(2,1),(2,-1),(-1,2),(-1,-2),(-2,1),(-2,-1));{m o v e[k,1..2]为马沿k⽅向跳跃⼀步的⽔平增量和垂直增量}
v a r
l i s t:a r r a y[0..20,0..20]o f c o m p;{路径数序列,其中l i s t[i,j]为卒从(0,0)到(i,j)的路径数}
c a n:a r r a y[0..20,0..20]o f b o o l e a n;{点(i,j)允许卒通⾏的标志}
马的初始位置为(x,y)。

我们按照下述⽅式计算c a n序列:
c a n[x,y]:=f a l s e;{对⽅马所在的点为控制点}
f o r i:=1t o8d o b e
g i n{从(x,y)出发,沿8个跳马⽅向计算控制点}
j:=x+m o v e[i,1];{计算i⽅向的跳马位置(j,k)}
k:=y+m o v e[i,2];
i f(j>=0)a n d(k>=0)a n d(j<=n)a n d(k<=m){若(j,k)在界内,则为控制点}
t h e n c a n[j,k]:=f a l s e;
e n d;{
f o r}
i f(n o t c a n[0,0])o r(n o t c a n[n,m]){若卒的起点和终点为控制点,则输出路径数0}
t h e n w r i t e l n(0)
e l s e b e g i n计算和输出卒从(0,0)⾛到(n,m)点的路径数l i s t[n,m];e n d;
2、计算和输出卒从(0,0)⾛到(n,m)点的路径条数:我们按照由上⽽下、由左⽽右的顺序,将卒可能到达的每⼀个位置(i,j)(0≤i≤n,0≤j≤m)设为阶段(状态)。

⾸先,将卒的出发点(0,0)的路径数设为1(l i s t[0,0]:=1).
然后从(0,0)出发,按照由上⽽下、由左⽽右的顺序计算卒经过每⼀个可⾏点的路径数。

若(i,j)为可⾏点,则卒可由上侧的(i-1,j)和左侧的(i,j-1)进⼊该点。

将这两点的路径数加起来,即为从(0,0)⾛到(i,j)的路径数,即
l i s t[i,j]=l i s t[i-1,j]+l i s t[i,j-1](i,j)⾮控制点
依次类推,最后得出的l i s t[n,m]即为问题的解。

由此得出算法:
f i l l c h a r(l i s t,s i z e o f(l i s t),0);{路径数序列初始化}
l i s t[0,0]:=1;{卒从(0,0)出发的路径数为1
f o r i:=0t o n d o{对于每个可⾏点,⼩兵要么从左侧、要么从上⽅⾛到,由此计算从(0,0)到(i,j)的路径数}
f o r j:=0t o m d o i f c a n[i,j]
t h e n l i s t[i,j]:=l i s t[i-1,j]+l i s t[i,j-1];
输出卒从(0,0)⾛到(n,m)点的路径条数l i s t[n,m];
例、骑⼠游历:(noip1997tg)
设有⼀个n*m的棋盘(2<=n<=50,2<=m<=50),如下图,在棋盘上任⼀点有⼀个中国象棋马,
马⾛的规则为:1.马⾛⽇字 2.马只能向右⾛,即如下图所⽰:
任务1:当N,M 输⼊之后,找出⼀条从左下⾓到右上⾓的路径。

例如:输⼊ N=4,M=4
输出:路径的格式:(1,1)->(2,3)->(4,4)
若不存在路径,则输出"no"
任务2:当N,M 给出之后,同时给出马起始的位置和终点的位置,试找出从起点到终点的所有路径的数⽬。

例如:(N=10,M=10),(1,5)(起点),(3,5)(终点)
输出:2(即由(1,5)到(3,5)共有2条路径)
输⼊格式:n,m,x1,y1,x2,y2(分别表⽰n,m,起点坐标,终点坐标)
输出格式:路径数⽬(若不存在从起点到终点的路径,输出0)
算法分析:为了研究的⽅便,我们先将棋盘的横坐标规定为i,纵坐标规定为j,对
于⼀个n×m的棋盘,i的值从1到n,j的值从1到m。

棋盘上的任意点都可以⽤坐
标(i,j)表⽰。

对于马的移动⽅法,我们⽤K来表⽰四种移动⽅向(1,2,3,4);⽽
dx和dy中,如下表
根据马⾛的规则,马可以由(i-dx[k],j-dy[k])⾛到(i,j)。

只要马能从(1,1)⾛到(i-dx[k],j-dy[k]),就⼀定能⾛到(i,j),马⾛的坐标必须保证在棋盘上。

以(n,m)为起点向左递推,当递推到(i-dx[k],j-dy[k])的位置是(1,1)时,就找到了⼀条从(1,1)到(n,m)的路径。

⽤⼀个⼆维数组a表⽰棋盘,对于任务⼀,使⽤倒推法,从终点(n,m)往左递推,设初始值a[n,m]为(-1,-1),如果从(i,j)⼀步能⾛到(n,m),就将(n,m)存放在a[i,j]中。

如下表,a[3,2]和a[2,3]的值是(4,4),表⽰从这两个点都可以到达坐标(4,4)。

从(1,1)可到达(2,3)、(3,2)两个点,所以a[1,1]存放两个点中的任意⼀个即可。

递推结束以后,如果a[1,1]值为(0,0)说明不存在路径,否则a[1,1]值就是马⾛下⼀
任务⼀的源程序:
const
dx:array[1..4]of integer=(2,2,1,1);
dy:array[1..4]of integer=(1,-1,2,-2);
type
map=record
x,y:integer;
end;
var
i,j,n,m,k:integer;
a:array[0..50,0..50]of map;
begin
read(n,m);
fillchar(a,sizeof(a),0);
a[n,m].x:=-1;a[n,m].y:=-1;{标记为终点}
for i:=n downto 2 do {倒推}
for j:=1 to m do
if a[i,j].x<>0 then
for k:=1 to 4 do
begin
a[i-dx[k],j-dy[k]].x:=i;
a[i-dx[k],j-dy[k]].y:=j;
end;
if a[1,1].x=0 then writeln('no')
else begin{存在路径}
i:=1;j:=1;
write('(',i,',',j,')');
while a[i,j].x<>-1 do
begin
k:=i;
i:=a[i,j].x;j:=a[k,j].y;
write('->(',i,',',j,')');
end;
end;
end.
对于任务⼆,也可以使⽤递推法,⽤数组A[i,j]存放从起点(x1,y1)到(i,j)的路径总数,按同样的⽅法从左向右递推,⼀直递推到(x2,y2),a[x2,y2]即为所求的解。

源程序(略)
在上⾯的例题中,递推过程中的某个状态只与前⾯的⼀个状态有关,递推关系并不复杂,如果在递推中的某个状态与前⾯的所有状态都有关,就不容易找出递推关系式,这就需要我们对实际问题进⾏分析与归纳,从中找到突破⼝,总结出递推关系式。

我们可以按以下四个步骤去分析:(1)细⼼的观察;(2)丰富的联想;(3)不断地尝试;(4)总结出递推关系式。

下⾯我们再看⼀个复杂点的例⼦。

例、栈(Stack.pas)(noip2003pj)
【问题背景】栈是计算机中经典的数据结构,简单的说,栈就是限制在⼀端进⾏插⼊删除操作的线性表。

栈有两种最重要的操作,即pop(从栈顶弹出⼀个元素)和push(将⼀个元素进栈)。

栈的重要性不⾔⾃明,任何⼀门数据结构的课程都会介绍栈。

宁宁同学在复习栈的基本概念时,想到了⼀个书上没有讲过的问题,⽽他⾃⼰⽆法给出答案,所以需要你的帮忙。

【问题描述】
1 2 3
输出序列尾端头端操作数序列
头端
栈A
宁宁考虑的是这样⼀个问题:⼀个操作数序列,从1,2,⼀直到n(图⽰为1到3的情况),栈A的深度⼤于n。

现在可以进⾏两种操作,
1.将⼀个数,从操作数序列的头端移到栈的头端(对应数据结构栈的push操作)
2. 将⼀个数,从栈的头端移到输出序列的尾端(对应数据结构栈的pop操作)
使⽤这两种操作,由⼀个操作数序列就可以得到⼀系列的输出序列。

你的程序将对给定的n,计算并输出由操作数序列1,2,…,n经过操作可能得到的输出序列的总数。

【输⼊格式】
输⼊⽂件只含⼀个整数n (1≤n ≤18)【输出格式】
输出⽂件只有⼀⾏,即可能输出序列的总数⽬【输⼊样例】3 【输出样例】5
算法分析:先模拟⼊栈、出栈操作,看看能否找出规律,我们⽤f(n)表⽰n 个数通过栈操作后的排列总数,当n 很⼩时,很容易模拟出f(1)=1;f(2)=2;f(3)=5,通过观察,看不出它们之间的递推关系,我们再分析N=4的情况,⼊栈前的排列为“1234”,按第⼀个数“1”在出栈后的位置进⾏分情况讨论:(1)若“1”最先输出,刚好与N=3相同,总数为f(3); (2)若“1”第⼆个输出,则在“1”的前只能是“2”,“34”在“1”的后⾯,这时可以分别看作是N=1
和N=2时的⼆种情况,排列数分别为f(1)和f(2),所以此时的总数为f(1)*f(2);
(3)若“1”第三个输出,则“1”的前⾯⼆个数为“23”,后⾯⼀个数为“4”,组成的排列总数为f(2)*f(1); (4)若“1”第四个输出,与情况(1)相同,总数为f(3); 所以有:f(4)=f(3)+f(1)*f(2)+f(2)*f(1)+f(3); 若设0个数通过栈后的排列总数为:f(0)=1;
上式可变为:f(4)=f(0)*f(3)+f(1)*f(2)+f(2)*f(1)+f(3)*f(0); 再进⼀步推导,不难推出递推式:
f(n)=f(0)*f(n-1)+f(1)*f(n-2)+…+f(n-1)*f(0); 即f(n)= (n>=1)
初始值:f(0)=1;
有了以上递推式,就很容易⽤递推法写出程序。

var
a:array[0..18]of longint; n,i,j:integer; begin
readln(n);
fillchar(a,sizeof(a),0); a[0]:=1;
for i:=1 to n do
for j:=0 to i-1 do a[i]:=a[i]+a[j]*a[i-j-1]; writeln(a[n]); end.
递推算法最主要的优点是算法结构简单,程序易于实现,难点是从问题的分析中找出解决问题的递推关系式。

对于以上两个例⼦,如果在⽐赛中找不出递推关系式,也可以⽤其它其它⽅法求解(如回溯)。

例、昆⾍繁殖(顺推)科学家在热带森林中发现了⼀种特殊的昆⾍,这种昆⾍的繁殖能⼒很强。

每对成⾍过x 个⽉产y 对卵,每对卵要过两个⽉长成成⾍。

假设每个成⾍不死,第⼀个⽉只有⼀对成⾍,且卵长成成⾍后的第⼀个⽉不产卵(过X 个⽉产卵),问过Z 个⽉以后,共有成⾍多少对?x >=1,y >=1,z >=x 输⼊:x ,y ,z 的数值输出:成⾍对数
样例:输⼊:x =1 y =2 z =8 输出:37
分析:⾸先我们来看样例:每隔1个⽉产2对卵,求过8⽉(即第8+1=9⽉)的成⾍个数设数组A [i ]表⽰第I ⽉新增的成⾍个数。

由于新成⾍每过x 个⽉产y 对卵,则可对每个A [I ]作如下操作:

-≤≤--10)1(*)(n i i n f i f
A [i +k *x +2]:=A [i +k *x +2]+A [i ]*y (1<=k , I +k *x +2<=z +1)因为A [i ]的求得只与A [1]~A [i -1]有关,即可⽤递推求法。

则总共的成⾍个数为:
v a r x ,y ,z ,i :i n t e g e r ; a n s :l o n g i n t ;
a :a r r a y [1..60]o f l o n g i n t ; p r o c e d u r e a d d (i :i n t e g e r ); v a r j :i n t e g e r ;
b e g i n
j :=i +2+x ; {新⽣成⾍要过x 个⽉才开始产卵,即第I +2+x 个⽉才出现第⼀群新成⾍} r e p e a t
a [j ]:=a [j ]+a [i ]*y ; {递推} j :=j +x u n t i l j >z +1 e n d ;
b e g i n
r e a d l n (x ,y ,z );
a [1]:=1; {初始化}
f o r i :=1 t o z d o a d d (i ); {对每个A [I ]进⾏递推} a n s :=0;
f o r i :=1 t o z +1 d o a n s :=a n s +a [i ]; {累加总和} w r i t e l n (a n s ); e n d .
传球游戏【问题描述】上体育课的时候,⼩蛮的⽼师经常带着同学们⼀起做游戏。

这次,⽼师带着同学们⼀起做传球游戏。

游戏规则是这样的:n 个同学站成⼀个圆圈,其中的⼀个同学⼿⾥拿着⼀个球,当⽼师吹哨⼦时开始传球,每个同学可以把球传给⾃⼰左右的两个同学中的⼀个(左右任意),当⽼师再次吹哨⼦时,传球停⽌,此时,拿着球没有传出去的那个同学就是败者,要给⼤家表演⼀个节⽬。

聪明的⼩蛮提出了⼀个有趣的问题:有多少种不同的传球⽅法可以使得从⼩蛮⼿⾥开始传的球,传了m 次后,⼜回到⼩蛮⼿⾥。

两种传球⽅法被视为不同的⽅法,当且仅当这两种⽅法中,接到球的同学按接球顺序组成的序列是不同的。

⽐如有3个同学1号、2号、3号,并假设⼩蛮为⼀号,球传了3次后回到⼩蛮⼿⾥的⽅式有 1-> 2-> 3-> 1 和1-> 3-> 2-> 1 ,共2种。

分析:
设f(i,k)表⽰经过k 次传球到编号为i 的⼈⼿中的⽅案数。

可以发现,传到i 号同学的球只能来⾃于i 的左边⼀个同学或者右边⼀个同学,这两个同学的编号分别是i-1、i+1,所以可以得到以下的递推公式: f(i,k)=f(i-1,k-1)+f(i+1,k-1) 当i=1或n 时,需单独处理:1. f(1,k)=f(2,k-1)+f(n,k-1) 2. f(n,k)=f(n-1,k-1)+f(1,k-1) 从1号同学开始传球,可确定初始条件:f(1,0)=1 可根据传球次数进⾏递推,结果在f(1,m)中。

var i,j,k,n,m:longint;
f:array[0..30,0..30] of longint; begin readln(n,m); fillchar(f,sizeof(f),0);
f[1,0]:=1;
∑+==1
1
]
[z i i A ans。

相关文档
最新文档