递推递归.docx
- 文档编号:2867630
- 上传时间:2022-11-16
- 格式:DOCX
- 页数:33
- 大小:30.79KB
递推递归.docx
《递推递归.docx》由会员分享,可在线阅读,更多相关《递推递归.docx(33页珍藏版)》请在冰豆网上搜索。
递推递归
1、遍历问题
源程序名travel.?
?
?
(pas,c,cpp)
可执行文件名travel.exe
输入文件名travel.in
输出文件名travel.out
【问题描述】
我们都很熟悉二叉树的前序、中序、后序遍历,在数据结构中常提出这样的问题:
已知一棵二叉树的前序和中序遍历,求它的后序遍历,相应的,已知一棵二叉树的后序遍历和中序遍历序列你也能求出它的前序遍历。
然而给定一棵二叉树的前序和后序遍历,你却不能确定其中序遍历序列,考虑如下图中的几棵二叉树:
aaaa
//\\
bbbb
/\/\
cccc
所有这些二叉树都有着相同的前序遍历和后序遍历,但中序遍历却不相同。
【输入】
输A数据共两行,第一行表示该二叉树的前序遍历结果s1,第二行表示该二叉树的后序遍历结果s2。
【输出】
输出可能的中序遍历序列的总数,结果不超过长整型数。
【样例】
trave1.intrave1.out
abc1
bca
【算法分析】
在肯定有解的情况下,上述算法最终可以递归调用到0、1个结点,如果有多组解,那么调用到两个结点时,如先序为ab、后序为ba,此时有可能有如下两种结构:
aa
/\
bb
这两种结构的中序遍历结果分别为:
ba、ab,有两种。
根据分步相乘的原理,对比两个字符串,每出现一次如上的情况,可能有的结构数目(结构不同,中序遍历结果也不同,因此可能有的二叉树结构的数目就是可能有的中序遍历结果数目)就乘以2一次,最终得到总的数目。
这也可以理解为一种递推的方法。
从这里可以看到,在肯定有解的情况下,给定先序遍历的结果和后序遍历的结果,可能有2n种可能的结构,也就是中序遍历可能得到2n种不同的结果,其中n>=0。
那么这里的n最大可能是多少呢?
可以证明n的最大值为字符串的长度加1整除2。
【参考程序】
programfgdjfk;
vari,j,m,sum:
longint;
s1,s2:
string;
begin
assign(input,'travel.in');
reset(input);
assign(output,'travel.out');
rewrite(output);
readln(s1);
readln(s2);
sum:
=1;
fori:
=1tolength(s1)-1do
begin
m:
=pos(s1[i],s2);
ifm>1then
ifs1[i+1]=s2[m-1]then
sum:
=sum*2;
end;
writeln(sum);
close(input);
close(output);
end.
2产生数
源程序名build.?
?
?
(pas,c,cpp)
可执行文件名build.exe
输入文件名build.in
输出文件名build.out
【问题描述】
给出一个整数n(n<1030)和m个变换规则(m≤20)。
约定:
一个数字可以变换成另一个数字,规则的右部不能为零,即零不能由另一个数字变换而成。
而这里所说的一个数字就是指一个一位数。
现在给出一个整数n和m个规则,要你求出对n的每一位数字经过任意次的变换(0次或多次),能产生出多少个不同的整数。
【输入】
共m+2行,第一行是一个不超过30位的整数n,第2行是一个正整数m,接下来的m行是m个变换规则,每一规则是两个数字x、y,中间用一个空格间隔,表示x可以变换成y。
【输出】
仅一行,表示可以产生的不同整数的个数。
【样例】
build.inbuild.out
1236
2
12
23
【算法分析】
如果本题用搜索,搜索的范围会很大(因为n可能有30位!
),显然无法在规定的时间内出解。
而我们注意到本题只需计数而不需要求出具体方案,所以我们稍加分析就会发现,可以用乘法原理直接进行计数。
设F[i]表示从数字i出发可以变换成的数字个数(这里的变换可以是直接变换,也可以是间接变换,比如样例中的1可以变换成2,而2又可以变换成3,所以1也可以变换成3;另外自己本身不变换也是一种情况)。
那么对于一个长度为m位的整数a,根据乘法原理,能产生的不同的整数的个数为:
F[a[1]]*F[a[2]]*F[a[3]]*…*F[a[m]]。
下面的问题是如何求F[i]呢?
由于这些变换规则都是反映的数字与数字之间的关系,所以定义一个布尔型的二维数组g[0..9,0..9]来表示每对数字之间是否可以变换,初始时都为False;根据输入的数据,如果数字i能直接变换成数字j,那么g[i,j]置为True,这是通过一次变换就能得到的;接下来考虑那些间接变换可得到的数字对,很明显:
如果i可以变为k,k又可以变为j,那么i就可以变为j,即:
fork:
=0to9do
fori:
=0to9do
forj:
=0to9do
g[i,j]=g[i,j]or(g[i,k]andg[k,j]);
最后还要注意,当n很大时,解的个数很大,所以要用高精度运算。
【参考程序】
programdrgjol;
vari,j,k,n,m,l:
longint;
a:
array[1..30]oflongint;//读入的数
f:
array[0..9]oflongint;//i对应的变换数目
g:
array[0..9,0..9]ofboolean;//变换规则
sum:
array[1..1000]oflongint;//储存答案
ch:
char;
proceduremul(k:
longint);//计算sum
vari,x:
longint;
begin
x:
=0;
fori:
=1toldo
begin
sum[i]:
=sum[i]*k+x;
x:
=sum[i]div10;
sum[i]:
=sum[i]mod10;
end;
whilex<>0do
begin
inc(l);
sum[l]:
=xmod10;
x:
=xdiv10;
end;
end;{mul}
begin
assign(input,'build.in');
reset(input);
assign(output,'build.out');
rewrite(output);
n:
=0;
fillchar(g,sizeof(g),false);
whilenotseekeolndo
begin
inc(n);
read(ch);
a[n]:
=ord(ch)-ord('0');
end;
readln(m);
fori:
=1tomdo
begin
readln(j,k);
g[j,k]:
=true;
end;
fork:
=0to9do
fori:
=0to9do
forj:
=0to9do
g[i,j]:
=g[i,j]or(g[i,k]andg[k,j]);//计算变换规则
fillchar(f,sizeof(f),0);
fori:
=0to9dog[i,i]:
=true;
fori:
=0to9do
forj:
=0to9do
ifg[i,j]theninc(f[i]);//统计数目
sum[1]:
=1;
l:
=1;
fori:
=1tondo//求sum
mul(f[a[i]]);
fori:
=ldownto1do//输出
write(sum[i]);
writeln;
close(input);
close(output);
end.
3出栈序列统计
源程序名stack.?
?
?
(pas,c,cpp)
可执行文件名stack.exe
输入文件名stack.in
输出文件名stack.out
【问题描述】
栈是常用的一种数据结构,有n个元素在栈顶端一侧等待进栈,栈顶端另一侧是出栈序列。
你已经知道栈的操作有两种:
push和pop,前者是将一个元素进栈,后者是将栈顶元素弹出。
现在要使用这两种操作,由一个操作序列可以得到一系列的输出序列。
请你编程求出对于给定的n,计算并输出由操作数序列1,2,…,n,经过一系列操作可能得到的输出序列总数。
【输入】【输出】
就一个数n(1≤n≤1000)。
一个数,即可能输出序列的总数目。
【样例】
stack.instack.out
35
【算法分析】
在第一章练习里,我们通过回溯的方法计算并输出不同的出栈序列,这里只要求输出不同的出栈序列总数目,所以我们希望能找出相应的递推公式进行处理。
从排列组合的数学知识可以对此类问题加以解决。
我们先对n个元素在出栈前可能的位置进行分析,它们有n个等待进栈的位置,全部进栈后在栈里也占n个位置,也就是说n个元素在出栈前最多可能分布在2*n位置上。
出栈序列其实是从这2n个位置上选择n个位置进行组合,根据组合的原理,从2n个位置选n个,有C(2n,n)个。
但是这里不同的是有许多情况是重复的,每次始终有n个连续的空位置,n个连续的空位置在2n个位置里有n+1种,所以重复了n+1次。
所以出栈序列的种类数目为:
C(2n,n)/(n+1)=2n*(2n-1)*(2n-2)…*(n+1)/n!
/(n+1)=2n*(2n-1)*(2n-2)*…*(n+2)/n!
。
考虑到这个数据可能比较大,所以用高精度运算来计算这个结果。
本题实际是一个经典的Catalan数模型。
有关Catalan数的详细解释请参考《组合数学》等书。
【参考程序】
programdfgdjk;
vari,j,n,m,l:
longint;
p:
array[2..2000]ofboolean;//素数表
sum:
array[1..2000]oflongint;//储存答案
a,b,c:
array[1..1000]oflongint;//素因子表
procedureprime;//计算1~2000内的素数
vari,j:
longint;
begin
fillchar(p,sizeof(p),true);
i:
=2;
whilei*i<=2000do
begin
j:
=i+i;
whilej<=2000do
begin
p[j]:
=false;
j:
=j+i;
end;
inc(i);
end;
m:
=0;
fori:
=2to2000do
ifp[i]then
begin
inc(m);
a[m]:
=i;
end;
end;{prime}
proceduremul(k:
longint);//高精乘法求sum
vari,x:
longint;
begin
x:
=0;
fori:
=1toldo
begin
sum[i]:
=sum[i]*k+x;
x:
=sum[i]div10;
sum[i]:
=sum[i]mod10;
end;
whilex<>0do
begin
inc(l);
sum[l]:
=xmod10;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 递归