ImageVerifierCode 换一换
格式:DOCX , 页数:13 ,大小:24.66KB ,
资源ID:19817589      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/19817589.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(函数的递归调用与分治策略解读文档格式.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

函数的递归调用与分治策略解读文档格式.docx

1、iostream.hint f(int x) return(f(x-1);main() cout=1时n!= 1 当N=0时再将这种关系翻译为代码,即一个函数:long f(int n) if (n=0) return(1); else return(n*f(n-1);步骤4完善程序 主要的递归函数已经完成,将程序依题意补充完整即可。/ex1.cpp int n; cinn;endl=3)。从键盘输入N,输出A(N)。分析递归关系十分明显,由A(N)的表达式给出。需要注意的是本例中对于N=3,A(N)的值与A(N-1)和A(N-2)都有关。代码/ex2.cpplong fibonacci(in

2、t x) if ( (x=1) | (x=2) ) return(fibonacci(x-1)+fibonacci(x-2); coutendlfibonacci(n); 例3Hanoi塔问题。 问题描述在霍比特人的圣庙里,有一块黄铜板,上面插着3根宝石针(分别为A号,B号和C号)。在A号针上从下到上套着从大到小的n个圆形金片。现要将A针上的金片全部移到C针上,且仍按照原来的顺序叠置。移动的规则如下:这些金片只能在3根针间移动,一次只能一片,且任何时候都不允许将较大的金片压在较小的上面。从键盘输入n,要求给出移动的次数和方案。分析由金片的个数建立递归关系。当n=1时,只要将唯一的金片从A移到C

3、即可。当n1时,只要把较小的(n-1)片按移动规则从A移到B,再将剩下的最大的从A移到C(即中间“借助”B把金片从A移到C),再将B上的(n-1)个金片按照规则从B移到C(中间“借助”A)。本题的特点在于不容易用数学语言写出具体的递归函数,但递归关系明显,仍可用递归方法求解。/ex3.cpphanoi(int n,char t1,char t2,char t3) if (n=1)1 t1 t3endl; hanoi(n-1,t1,t3,t2);n hanoi(n-1,t2,t1,t3); Please enter the number of Hanoi:;Answer: hanoi(n,A,B

4、C);函数递归调用的应用与分治策略许多算法都采用了分治策略求解,而可以说分治与递归是一对孪生兄弟,它们经常同时被应用于算法的设计中。下面讨论著名的Catalan数问题,人们在对它的研究中充分应用了分治策略。例4Catalan数问题。问题描述一个凸多边形,通过不相交于n边形内部的对角线,剖分为若干个三角形。求不同的剖分方案总数H(n)。H(n)即为Catalan数。例如,n=5时H(5)=5。分析Catalan数问题有着明显的递归子问题特征。在计算Catalan数时虽然可以推导出只关于n的一般公式,但在推导过程中却要用到递归公式。下面讨论三种不同的解法,其中第三种解法没有使用递归,它是由前两种解

5、法推导而出的。解法1对于多边形V1V2Vn,对角线V1Vi(i=3,4,n-1)将其分为两部分,一部分是i边形,另一部分是n-i+1边形。因此,以对角线V1Vi为一个剖分方案的剖分方案数为H(i)*H(n-i+1)。还有一种的特殊情形,是对角线V2Vn将其分为一个三角形V1V2Vn和一个n-2+1边形。为了让它同样符合粗体字给出的公式,规定H(2)=1。于是得到公式:H(n)=H(i)*H(n-i+1) (i=2,3,n-1) -公式(1)H(2)=1有了这个递归关系式,就可以用递推法或递归法解出H(n)。解法2从V1向除了V2和Vn外的n-3个顶点可作n-3条对角线。每一条对角线V1Vi把多

6、边形剖分成两部分,剖分方案数为H(i)*H(n-i+2),由于Vi可以是V3V4Vn-1中的任一点,且V1可换成V2,V3,Vn中任一点也有同样的结果。考虑到同一条对角线在2个顶点被重复计算了一次,于是对每个由顶点和对角线确定的剖分方案都乘以1/2,故有H(n)=n(1/2)H(i)*H(n-i+2) (i=3,4,n-1)把(1/2)提到外面,H(n)=n/(2*(n-3)H(i)*H(n-i+2) (i=3,4,n-1) -公式(2)规定H(2)=H(3)=1,这是合理的。由公式(2)和H(2)=1,同样可以用递推法或递归法解出H(n)。解法3 把公式(1)中的自变量改为n+1,再将刚刚得

7、出的公式(2)代入公式(1),得到H(n+1)=H(i)*H(n-i+2) (i=2,3,n) 由公式(1)H(n+1)=2*H(n)+H(i)*H(n-i+2) (i=3,4,n-1) 由H(2)=1H(n+1)=(4n-6)/n*H(n) 由公式(2)H(n)=(4n-10)/(n-1)*H(n-1) -公式(3)这是一个较之前两种解法更为简单的递归公式,还可以继续简化为H(n)=1/(n-1)*C(n-2,2n-4) -公式(4)这就不需要再使用递归算法了。然而在程序设计上,公式(4)反而显得更加复杂,因为要计算阶乘。因此最后给出由公式(3)作为理论依据范例程序代码。代码相当简单,这都归

8、功于刚才的推导。如果用前两种解法中的递归关系,程序会变得复杂且容易写错。因此,有时对具体问题将递归关系公式进行必要的化简也是至关重要的。/ex4.cpp#define MAXN 100long f(int x) if (x=3) return(4*x-10)*f(x-1)/(x-1);nPlease input N for a Catalan number: if ( (n=3) )The answer is:本例编程时还有一个细节问题需要注意。注意函数f中的斜体部分,按照公式(4)计算时一定要先进行乘法再进行除法运算,因为(4*x-10)并不总能整除(x-1),如果先进行除法则除出的小数部分

9、将自动被舍去,从而导致得到不正确的解。数学上许多有重要意义的计数问题都可以归结为对Catalan数的研究。可以看到,本例中的递归关系经简化还是相当简单的。下面讨论一个递归关系略为复杂的例子。例5快速排序问题。快速排序是程序设计中经常涉及的一种排序算法。它的最好时间复杂度为O(nlog2n),最差为O(n2),是一种不稳定的排序方法(大小相同的数在排序后可能交换位置)。算法描述快速排序的一种基本思想是:要将n个数按由小到大排列,在待排序的n个数中选取任一个数(在本例中取第一个),称为基准数,在每一次快速排序过程中设置两个指示器i和j,对基准数左边和右边的数同时从最左(i)和最右(j)开始进行扫描

10、(i逐1递增,j逐1递减),直到找到从左边开始的某个i大于或等于基准数,从右边开始的某个j小于或等于基准数。一旦发现这样的i和j(暂且称之为一个“逆序对”),则把第i个数和第j个数交换位置,这样它们就不再是逆序对了,紧接着再将i递增1,j递减1。如此反复,在交换过有限个逆序对后,i和j将越来越靠近,最后“相遇”,即i和j指向同一个数,暂且称之为相遇数(极端情况下,如果一开始就不存在逆序对,i和j将直接“相遇”)。相遇后就保证数列中没有逆序对了(除了在上述的极端情况下基准数和自身也算构成一个逆序对,注意粗体字给出的逆序对的定义)。继续扫描,非极端情况下,由于数列中已经没有逆序对,i递增1(如果相

11、遇数小于基准数)或者j递减1(如果相遇数大于基准数)后即算完成了一趟快速排序,这时第1到第j个数中的每个都保证小于或等于基准数,第i到第n个数中的每个保证大于或等于基准数。此时,递归调用函数,对第1到第j个数和第i到第n个数分别再进行一趟快速排序。如果在极端情况下,程序认为基准数和自身构成逆序对,则将基准数与自身交换(这其实没有作用)之后i递增1,j递减1(注意斜体字给出的对逆序对的处理方法),同样对第1到第j个数和第i到第n个数分别再进行一趟快速排序。最后的问题就是确定递归边界。由于被排序的数列将不断被划分为两个至少含一个数的子列(因为在每趟排序最后进行递归调用函数时ij),最后子列的长度将

12、变为1。这就是递归的边界。在程序实现是,本着“能排则排”的原则,只要第一个数小于j(或者第i个数小于最后一个数),即进行递归。主程序(递归函数体)/ex5.cpp (part)qksort(int l,int r) int i,j,v,s; i=l; j=r; v=al; do while (aiv) j-; if (i=j) s=ai; ai=aj; aj=s; i+; j-; while (i=j); if (lj) qksort(l,j);r) qksort(i,r); 例6“九宫阵”智力游戏。问题描述一个99方阵,由9个“九宫格”组成,每个九宫格又由33共9个小格子组成。请在每个空白小

13、格子里面填上19的数字,使每个数字在每个九宫格内以及在整个九宫阵中的每行、每列上均出现一次。(1)编程将下面图中的九宫阵补充完整。(2)讨论是否可能给出“九宫阵”的全部解?945736812分析本题可利用回溯法解决,其基本思想为深度优先搜索(DFS),这也是一种以分治策略为基础的算法。回溯法与纯粹的DFS不同的是,它在搜索过程中不断杀死不合题意的结点。这一点保证了解法的效率。首先考虑如何得出全部解的情况。解空间树容易构造,只需按顺序(从第一行第一个数字开始到第一行最后一个,然后第二行,一直到最后一行最后一个数字)“尝试”填入数字即可。为了解决这个问题,我们需要先编写一个函数check,其原型为

14、int check(int i,int j,int k),用于求第i行第j列能否填上数字k。如果可以,返回1,否则返回0。由于我们是按顺序填入数字的,看起来一个数字后面的数字并不在判断能否填的范围内。但为了解决题中某个特解问题的方便,还是引入较为严谨的判断方法。函数check代码如下:int check(int i,int j,int k) int l,m,pi,pj; /1. Check the line for (l=1;l=9;l+) if ( (l!=j) & (ail!=0) & (ail=k) ) return(0); /2. Check the column=i) & (alj!

15、 (alj=k) ) /3. Check the 3x3 matrix /3.1 Firstly we will have to check the parent_i(pi) and parent_j(pj)=3) pi=1; else if (i=6) pi=4; else pi=7; if (j=3) pj=1; else if (j=6) pj=4; else pj=7; /3.2 Now we can check it for (l=0;=2; for (m=0;mm+) if ( (pi+l)! (pj+m)!=j) ) if ( ( api+lpj+m!=0 ) & ( api+l

16、pj+m=k ) ) return(0);结合注释很容易就能接受函数的思想,不予过多说明。下面考虑程序最重要的部分,即递归函数。思路是这样的:假设某一格能填入某数,把这个格子看成解空间树的一个结点,由它可以扩展出9个儿子,即下一格填什么数(由1到9逐个尝试)。对下一格,同样这样考虑。不断用函数check函数考察某一个能否填入某数,一旦函数check返回0,则杀死这个结点。如果能一直填到最后一个数,结点仍未被杀死,则这是一个解。这种思想可用伪代码表示如下:procedure backtrack(i,j,k:integer); if check(i,j,k)=true then begin ai,

17、j=k; Generate_next_i_and_j; if i10 then for l:=1 to 9 do backtrack(i,j,l);endelse Do_Output;ai,j:=0; end;注意斜体的“ai,j:=0”必不可少!当对某个结点(x,y)扩展的过程中,可能在扩展到(x+m,y+n)时它的子树被完全杀死(每个结点都被杀死,亦即按照(x,y)及之前的填数方案填数,无解)。这时需要保证(x,y)以后所填的数被重新置零,这个语句的作用即在每个结点被杀死时都将其置零。将伪代码翻译为C+代码:backtrack(int i,int j,int k) int l; if (c

18、heck(i,j,k)=1) aij=k; /Fill in the okay solution /Generate next i,j9) j+; else i+; j=1; /End of Generate next i,j10) backtrack(i,j,l); output(); aij=0; /*When fails and goes upperwards, the value must be cleared*/函数output()用双重循环完成输出。在主函数main()对backtrack(1,1,i)进行一个循环,i从1取到9,即可完成整个程序。运行时发现九宫格的解相当多,即使保

19、存到文件中也不现实。这就回答了第2个问题。对于第1个问题,将这个程序略加改动,即赋予全局数组a以初值,并在过程backtrack中产生下一个i和j时跳过有初值的部分,即可将程序转化为求填有部分空缺的九宫格程序。最后给出填充有部分空缺的九宫格的完整源代码。/ex6-1.cppint a1111=0;output() int i,j;One solution is: for (i=1;ii+) for (j=1;jj+)aij do while (aij!=0); /End of Generate next i,jinit() a12=9; a16=4; a17=5; a19=7; a23=3;

20、a25=7; a26=9; a27=4; a34=3; a35=6; a38=8; a39=9; a41=3; a44=1; a53=4; a58=2; a59=3; a62=1; a63=2; a66=3; a71=8; a78=5; a82=6; a84=2; a85=9; a92=2; a93=1; a97=8; int i;i+) init(); backtrack(1,1,i); 递归方法在算法与数据结构中的应用无所不在,如动态规划(状态方程)、回溯法(深度优先搜索)等等,以上两例只是冰山一角。只有熟悉掌握函数递归调用的编程方法,深入理解分治策略的重要思想,才能编写出功能强大、高效简明的程序。

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

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