好文档就是一把金锄头!
欢迎来到金锄头文库![会员中心]
电子文档交易市场
安卓APP | ios版本
电子文档交易市场
安卓APP | ios版本

NOIP基础算法--枚举、递推和递归教程课件.ppt

115页
  • 卖家[上传人]:博****1
  • 文档编号:568595946
  • 上传时间:2024-07-25
  • 文档格式:PPT
  • 文档大小:654.50KB
  • / 115 举报 版权申诉 马上下载
  • 文本预览
  • 下载提示
  • 常见问题
    • NOIP基础算法综合 第一部分第一部分枚举策略枚举策略 一、枚举法的基本思想一、枚举法的基本思想n枚举法的基本思想是根据提出的问题枚举所有可能状态,并用问题给定的条件检验哪些是需要的,哪些是不需要的能使命题成立,即为其解n枚举结构:循环+判断语句 二、枚举法的条件二、枚举法的条件:n虽然枚举法本质上属于搜索策略,但是它与后面讲的回溯法有所不同因为适用枚举法求解的问题必须满足两个条件:n⑴可预先确定每个状态的元素个数n;n⑵状态元素a1,a2,…,an的可能值为一个连续的值域 三、枚举法的框架结构三、枚举法的框架结构n设ai1—状态元素ai的最小值;aik—状态元素ai的最大值(1≤i≤n),即a11≤a1≤a1k,a21≤a2≤a2k, ai1≤ai≤aik,……,an1≤an≤ankfor a1←a11 to a1k do      for a2←a21 to a2k do            ……………………              for ai←ai1 to aik do                    ……………………                       for an←an1 to ank do                              if 状态(a1,…,ai,…,an)满足检验条件                                                    then 输出问题的解; 枚举法的优点枚举法的优点n⑴由于枚举算法一般是现实生活中问题的“直译”,因此比较直观,易于理解;n⑵由于枚举算法建立在考察大量状态、甚至是穷举所有状态的基础上,所以算法的正确性比较容易证明。

      枚举法的缺点枚举法的缺点n枚举算法的效率取决于枚举状态的数量以及单个状态枚举的代价,因此效率比较低四、枚举法的优缺点四、枚举法的优缺点 n“直译”枚举:直接根据题意设定枚举对象、范围和约束条件n 注意认真审题,不要疏漏任何条件 例题例题1:砝码称重:砝码称重(noip1996) 【【问题描述问题描述】】设有1g、2g、3g、5g、10g、20g的砝码各若干枚(其总重<=1000),求用这些砝码能称出不同的重量个数文件输入文件输入】】输入1g、2g、3g、5g、10g、20g的砝码个数文件输出文件输出】】输出能称出不同重量的个数样例输入样例输入】】1 1 0 0 0 0【【样例输出样例输出】】3 【【分析分析】】根据输入的砝码信息,每种砝码可用的最大个数是确定的,而且每种砝码的个数是连续的,能取0到最大个数,所以符合枚举法的两个条件,可以使用枚举法枚举时,重量可以由1g,2g,……,20g砝码中的任何一个或者多个构成,枚举对象可以确定为6种重量的砝码,范围为每种砝码的个数判定时,只需判断这次得到的重量是新得到的,还是前一次已经得到的,即判重由于重量<=1000g,所以,可以开一个a[1001]的数组来判重。

      核心参考代码:核心参考代码:readln(a,b,c,d,e,f)for c[1]:=0 to a do //1g砝码的个数砝码的个数 for c[2]:=0 to b do //2g砝码的个数砝码的个数 for c[3]:=0 to c do //3g砝码的个数砝码的个数 for c[4]:=0 to d do //5g砝码的个数砝码的个数 for c[5]:=0 to e do //10g砝码的个数砝码的个数 for c[6]:=0 to f do //20g砝码的个数砝码的个数 begin sum:=0; for i:=1 to 6 do sum:=sum+c[i]*w[i]; a[sum]:=1; //标记标记 end;for i:=1 to 1000 do if a[i]=1 then inc(num); //统计不同重量的个数统计不同重量的个数Writeln(num); 【问题描述】给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A、B、C是用火柴棍拼出的整数(若该数非零,则最高位不能是0)。

      用火柴棍拼数字0-9的拼法如图所示:注意:     1. 加号与等号各自需要两根火柴棍     2. 如果A≠B,则A+B=C与B+A=C视为不同的等式(A、B、C≥0)      3. n根火柴棍必须全部用上【输入】输入文件matches.in共一行,又一个整数n(n≤24)输出】输出文件matches.out共一行,表示能拼成的不同等式的数目 例题例题2:火柴棒等式(:火柴棒等式(NOIP2008)) 例题例题2:火柴棒等式(:火柴棒等式(NOIP2008)) 【【问题简述问题简述】】给你n(n<=24)根火柴棒,叫你拼出 “A + B = C”这样的等式,求方案数 【【思路点拨思路点拨】】本题主要考查对枚举法的掌握,可以枚举A和B的取值,考查等式是否刚好用了24根火柴棒1S的时限对枚举的范围有所要求,必须要仔细分析A和B的取值 例题例题2:火柴棒等式(:火柴棒等式(NOIP2008))n本题最多24根火柴,等号和加号共用4根火柴,所以A,B,C这3个数字需用20根火柴我们考查A和B的最大的取值可能:0~9这10个数字所用的火柴数为6,2,5,5,4,5,6,3,7,6,很明显数字1用的火柴棒最少只要2根,不妨让B为1,那么A和C最多可以使用18根火柴,而C>=A,满足条件的A的最大取值为1111。

      所以枚举A和B的范围是从0~1111n为了加快速度,可以将为了加快速度,可以将0到到2222的所有整数需要的所有整数需要的火柴棒数目提前算好保存在数组中的火柴棒数目提前算好保存在数组中 五、枚举算法的优化枚举算法的优化 枚举算法的时间复杂度:状态总数*单个状态的耗时n⑴提取有效信息;n⑵减少重复计算;n⑶将原问题化为更小的问题;n⑷根据问题的性质进行截枝;n⑸引进其他算法 【【例题例题3】】给你给你n(n<=105)个整数,然后要有个整数,然后要有m (m<=105)个询问每个询问两个整数个询问每个询问两个整数i和和j,问第,问第i个个数字到第数字到第j个数字所有数字之和个数字所有数字之和朴素算法朴素算法】】 readln(n); for i:=1 to n do read(a[i]); for i:=1 to m do begin read(x,y); sum:=0; for j:=x to y do sum:=sum+a[j]; writeln(sum); end;时间复杂度为:时间复杂度为:O(nm) 【【优化算法优化算法】】先递推计算出先递推计算出s[i]=s[i-1]+a[i],再回答询问情况,再回答询问情况; readln(n); for i:=1 to n do{统计求和统计求和} begin read(a[i]); s[i]:=s[i-1]+a[i]; end; for i:=1 to m do begin read(x,y); writeln(s[y]-s[x-1]); end; 【【例题例题4】】对于给定的对于给定的N*M的矩形,在其中找一个的矩形,在其中找一个R*C的权值最大的区域的权值最大的区域, 1<=N,M<=1,000。

      算法一算法一】】:以每一个格子为左上角枚举:以每一个格子为左上角枚举R*C的区的区域,并求出它的权值之和最后取其中的最大值域,并求出它的权值之和最后取其中的最大值此算法包含此算法包含4重循环 时间复杂度:时间复杂度:O(N^4) 【【算法二算法二】】:我们设:我们设S[i,j]表示以表示以(1,1)为左上角,为左上角,(i,j)为右为右下角区域的权值之和,那么我们以下角区域的权值之和,那么我们以(i,j)为右下角的为右下角的R*C区区域权值之和的计算公式为:域权值之和的计算公式为: Area[i,j]=S[i,j]+S[i-R,j-C]-S[i-R,j]-S[i,j-C]其中其中S[i,j]的计算公式为:的计算公式为: S[i,j]=value[i,j]+S[i-1,j]+S[i,j-1]-S[i-1,j-1] 你可以随手画图出来,很容易即可证明上面两个式子你可以随手画图出来,很容易即可证明上面两个式子最后取最后取Area[ ]中的最大值即可中的最大值即可 时间复杂度:时间复杂度:O(N^2) 【【例题例题5】】最大连续子序列的和最大连续子序列的和 【问题描述】给你一个有n(n<=100000)个整数的序列,要求你求出其中最大连续子序列的和。

        【算法1】枚举起始位置,结束位置,计算中间的和时间复杂度O(n^3) maxx:=a[1]; for i:=1 to n do for j:=i to n do begin sum:=0; for k:=i to j do sum:=sum+a[k]; if sum>maxx then maxx:=sum; end; 【算法算法2]:优化的枚举:优化的枚举——O(n^2) s[0]:=0; for i:=1 to n do s[i]:=s[i-1]+a[i];//初始化求和初始化求和 maxx:=a[1]; for i:=1 to n do for j:=i to n do if s[j]-s[i-1]>maxx then maxx:=s[j]-s[i-1];时间复杂度:预处理+主程序=O(n+n^2)=O(n^2),n<=5000 【算法3】分治分治——O(nlogn)、、 最大连续子序列的位置有三种可能: ①完全处于序列的左半; ②完全处于序列的右半; ③跨越序列中间; 【【算法算法4】】DP——O(n) 1、阶段和状态、阶段和状态: 以第i个数结尾的最大连续子序列的和,只存在两种选择: 情形1:只包含a[i] 情形2:包含a[i]和以a[i-1]结尾的最大连续和序列 故设f[i]表示以a[i]结尾的最大连续子序列的和 2、状态转移方程:、状态转移方程: 转移方程:f[i]=max{a[i],f[i-1]+a[i]}(2<=i<=n) 初始化:f[1]=a[1] Answer=max{f[i]|1<=i<=n} 【【例题例题6】】最大子矩阵问题最大子矩阵问题 【【问题描述问题描述】】给定一个二维的数组(含正数或负数),请从中找出和最大的子矩阵。

      例如: 1 1 1 1、、、、““““直译直译直译直译””””枚举过程枚举过程枚举过程枚举过程For x1:=1 to n do//枚举矩形左上角枚举矩形左上角(x1,y1) for y1:=1 to n do for x2:=1 to n do//枚举矩形右下角枚举矩形右下角(x2,y2) for y2:=1 to n do //考察状态左上角为考察状态左上角为(x1,y1)右下角为右下角为(x2,y2)内矩形的元素之和;内矩形的元素之和; begin sum:=0;; for x:=x1 to x2 do//计算当前矩形内元素的和计算当前矩形内元素的和 for y:=y1 to y2 do sum:=sum+a[x,y];; if sum>best then best:=sum;;//调整最优解调整最优解 end;n这个算法相当粗糙,枚举状态的费用为这个算法相当粗糙,枚举状态的费用为O(n6)(x1,y1)(x2,y2) 2 2、从减少重复计算入手、从减少重复计算入手 n有刚才一维情况可以推广到二维,在统计左上角为有刚才一维情况可以推广到二维,在统计左上角为(x1,y1)右下角右下角为为(x2,y2)内矩形的元素之和时,我们同样可以先初始化,计算出左内矩形的元素之和时,我们同样可以先初始化,计算出左上角为上角为(1,1),右下角为,右下角为(x,y)内矩形的元素之和内矩形的元素之和s[x][y]。

      for i:=1 to n do //枚举矩形右下角,求和枚举矩形右下角,求和 for j:=1 to n do begin read(a[i,j]); s[i,j]:=s[i-1,j]+s[i,j-1]-s[i-1,j-1]+a[i,j]; end;n对于状态左上角为对于状态左上角为(x1,y1),右下角为右下角为(x2,y2)内矩形的元素之和,可内矩形的元素之和,可以改为:以改为: sum:=s[x2,y2]-s[x1-1,y2]-s[x2,y1-1]+s[x1-1,y1-1]; if sum>best then best:=sum;; //调整最优解调整最优解n由于先进行了由于先进行了预处理预处理预处理预处理,整个算法的时间复杂度降为,整个算法的时间复杂度降为O(n4) 3、提取恰当的信息、提取恰当的信息n容易观察到,最大子矩阵问题是最大连续子序列和问题的提升,即将一条线换成一个面,将一维问题提升到二维问题所以我们计算最大子矩阵的方法就是将一行行的数进行累加以求得最大值。

      n但是还有一个问题,那就是应该如何高效地存储矩阵?n我们可以想到:在一个一维的数列中,设数组b[i]表示从第1个元素到第i个元素的和,则如果想要求第i个元素到第j个元素的和,只需要计算b[j]-b[i-1]的值就行了由此推广到二维矩阵,设b[i,j]表示矩阵第j列前i个元素的和,a[i,j]表示元素数据,则压缩存储: for i:=1 to n do for j:=1 to n do begin read(a[i,j]);b[i,j]:=b[i-1,j]+a[i,j];}n因此,我们可以使用三重循环求出所有的矩形值,即枚举起始行枚举起始行i和终和终止行止行j,压缩子矩形成为一行,变成一维求最大子段和问题,压缩子矩形成为一行,变成一维求最大子段和问题       即t[k]=max(t[k-1],0)+b[j,k]-b[i-1,k];n时间复杂度为O(n3) 0 -2 -7 09 2 -6 2-4 1 -4 1-1 8 0 -20 -2 -7 09 0 -13 25 1 -17 34 9 -17 1 ②②核心代码核心代码 sum:=-99999999; //置初值置初值 for i:=1 to n do //阶段阶段:起始行起始行 begin for j:=i to n do //状态状态:结束行结束行 begin t[1]:=b[j,1]-b[i-1,1]; //初始化第初始化第1列的值列的值 for k:=2 to n do //决策决策:第几列第几列 begin if t[k-1]>0 then t[k]:=t[k-1]+b[j,k]-b[i-1,k] else t[k]:=b[j,k]-b[i-1,k]; if t[k]>sum then sum:=t[k]; end; end; end; writeln(sum); 六、局部枚举六、局部枚举例题例题7:求第一、第二、第三最短路问题:求第一、第二、第三最短路问题 例题例题8:新年好:新年好n重庆城里有重庆城里有n个车站,个车站,m条双向公路连接其中的某些车站。

      条双向公路连接其中的某些车站每两个车站最多用一条公路直接相连,从任何一个车站出每两个车站最多用一条公路直接相连,从任何一个车站出发都可以经过一条或多条公路到达其他车站,但不同的路发都可以经过一条或多条公路到达其他车站,但不同的路径需要花费的时间可能不同在一条路上花费的时间等于径需要花费的时间可能不同在一条路上花费的时间等于路径上所有公路需要的时间之和路径上所有公路需要的时间之和n佳佳的家在车站佳佳的家在车站1,他有五个亲戚,分别住在车站,他有五个亲戚,分别住在车站a,b,c,d,e过年了,他需要从自己的家出发,拜访每个亲戚(顺序任过年了,他需要从自己的家出发,拜访每个亲戚(顺序任意),给他们送去节日的祝福怎样走,才需要最少的时意),给他们送去节日的祝福怎样走,才需要最少的时间?间?n数据范围:数据范围:n(n<=50,000),m(m<=100,000) 算法框架为:算法框架为:n((1)用)用6次计算单源最短路算法,即枚举这次计算单源最短路算法,即枚举这6个个点,每个点都做为源点求单源最短路点,每个点都做为源点求单源最短路n((2)枚举()枚举(a,b,c,d,e)这)这5个结点的全排列,个结点的全排列,找到一个使得总路程长度最短的方案。

      找到一个使得总路程长度最短的方案n 这一题中的边数远小于这一题中的边数远小于n2,所以复杂度也只有,所以复杂度也只有nlogn+m 第二部分第二部分递推策略递推策略 一、引例:一、引例:Fibonacci数列数列 nFibonacci数列的代表问题是由意大利著名数学家Fibonacci于1202年提出的“兔子繁殖问题”(又称“Fibonacci问题”)n问题:          一个数列的第0项为0,第1项为1,以后每一项都是前两项的和,这个数列就是著名的裴波那契数列,求裴波那契数列的第N项  解答n由问题,可写出递推方程n算法:算法: f[0]:=1; f[1]:=2; for i:=2 to n do f[i]:=f[i–1]+f[i–2]; 总结总结n从这个问题可以看出,在计算裴波那契数列的每一项目时,都可以由前两项推出这样,相邻两项之间的变化有一定的规律性,我们可以将这种规律归纳成如下简捷的递推关系式:Fn=g(Fn-1),这就在数的序列中,建立起后项和前项之间的关系然后从初始条件(或是最终结果)入手,按递推关系式递推,直至求出最终结果(或初始值)。

      很多问题就是这样逐步求解的n对一个试题,我们要是能找到后一项与前一项的关系并清楚其起始条件(或最终结果),问题就可以递推了,接下来便是让计算机一步步了让高速的计算机从事这种重复运算,真正起到“物尽其用”的效果 二、递推概念二、递推概念n给定一个数的序列给定一个数的序列H0,H1,…,Hn,…若存在整数若存在整数n0,使当,使当n>n0时时,可以用等号可以用等号(或大于号、小于号或大于号、小于号)将将Hn与其前面的某些项与其前面的某些项Hi(0

      n<=60)(一)递推的应用(一般递推问题)(一)递推的应用(一般递推问题)n思考:当思考:当n<=10n<=109 9时,如何求解时,如何求解? ? (一)(一)(一)(一)递推的应用(一般递推问题)递推的应用(一般递推问题) 例题例题2:输出杨辉三角的前:输出杨辉三角的前N行行 【【问题描述问题描述】】输出杨辉三角的前N行(N<10)文件输入文件输入】】输入只有一行,包括1个整数N(N<10)文件输出文件输出】】输出只有N行样例输入样例输入】】3 【【样例输出样例输出】】 1 1 1 1 2 1 递推方程:递推方程:f[i,j]=f[i-1][j-1]+f[i-1,j]边界条件:边界条件:f[i,1]=1;f[i,i]=1 (一)(一)(一)(一)递推的应用(一般递推问题)递推的应用(一般递推问题)n例题例题3 : Hanoi塔问题塔问题 . Hanoi塔由n个大小不同的圆盘和三根木柱a,b,c组成开始时,这n个圆盘由大到小依次套在a柱上,如图1所示要求把a柱上n个圆盘按下述规则移到c柱上: (1)一次只能移一个圆盘; (2)圆盘只能在三个柱上存放; (3)在移动过程中,不允许大盘压小盘。

      问将这n个盘子从a柱移动到c柱上,总计需要移动多少个盘次?                        a                  b                  c                                                  图1 分析分析ABC213当当当当n=1n=1时:时:时:时:A AC C当当当当n=2n=2时:时:时:时:A AB,AB,AC,BC,BC C当当当当n=3n=3时:时:时:时: 分析分析n设f(n)为n 个盘子从1柱移到3柱所需移动的最少盘次n当n=1时,f(1)=1n当n=2时,f(2)=3n以此类推,当1柱上有n(n>2)个盘子时,我们可以利用下列步骤:n第一步:先借助3柱把1柱上面的n-1个盘子移动到2柱上,所需的                    移动次数为f(n-1)n第二步:然后再把1柱最下面的一个盘子移动到3柱上,只需要1                    次盘子n第三步:再借助1柱把2柱上的n-1个盘子移动到3上,所需的移动                     次数为f(n-1)。

      n由以上3步得出总共移动盘子的次数为:f(n-1)+1+ f(n-1)n所以:f(n)=2 f(n-1)+1                 hn=2hn-1+1 =2n-1                边界条件:h1=1 【【扩展扩展1】】:: Hanoi双塔问题双塔问题 【【扩展扩展2】】:四塔问题:四塔问题 【【问题分析问题分析】】令令f[i]表示四个柱子时,把表示四个柱子时,把i个盘子从原柱移动到目标柱所需的最个盘子从原柱移动到目标柱所需的最少移动次数少移动次数 jn第一步:先把1柱上的前j个盘子移动到另外其中一个非目标柱(2或3柱均可,假设移到2柱)上,此时3和4柱可以作为中间柱移动次数为:f[j]n第二步:再把原1柱上剩下的i-j个盘子在3根柱子(1、3、4)之间移动,最后移动到目标柱4上,因为此时2柱不能作为中间柱子使用,根据三柱问题可知,移动次数为:2^(i-j)-1n第三步:最后把非目标柱2柱上的j个盘子移动到目标柱上,次数为:f[j] i n通过以上步骤我们可以初步得出:通过以上步骤我们可以初步得出: f[i] = 2*f[j]+2^(i-j)-1nj可取的范围是可取的范围是1<=j

      是不同的,本题要求最少的移动次数  f[i]=min{2*f[j]+2^(i-j)-1},其中1<=j

      n分析上数据,可得递推公式: h[i]=1+h[1]+h[2]+…+h[i/2]n时间复杂度O(n2) 方法方法2:是对方法:是对方法1的改进的改进我们定义数组s s(x)=h(1)+h(2)+…+h(x) =s(x-1)+h(x) =s(x-1)+s(x/2) h(x)=s(x)-s(x-1)=s(x/2) 此算法的时间复杂度可降到O(n) 方法方法3:还是用递推:还是用递推n只要做仔细分析,其实我们还可以得到以下的递推公式: (1)当i为奇数时,h(i)=h(i-1); (2) 当i为偶数时,h(i)=h(i-1)+h(i/2); 【【思考思考】】 1.若若n<=10000怎么计算;怎么计算; 2.若若n<=3000000怎么计算;怎么计算; (一)递推的应用(一般递推问题)(一)递推的应用(一般递推问题)n例题例题5:猴子吃桃问题:猴子吃桃问题1538n【【问题描述问题描述】】猴子摘了一堆桃,第一天吃了一半,猴子摘了一堆桃,第一天吃了一半,还嫌不过瘾,又吃了一个;第二天又吃了剩下的还嫌不过瘾,又吃了一个;第二天又吃了剩下的一半零一个;以后每天如此。

      到第一半零一个;以后每天如此到第n天,猴子一看天,猴子一看只剩下一个了问最初有多少个桃子?只剩下一个了问最初有多少个桃子? 【【扩展练习扩展练习】】猴子分桃猴子分桃 【【问题描述问题描述】】有一堆桃子和N只猴子,第一只猴子将桃子平均分成了M堆后,还剩了1个,它吃了剩下的一个,并拿走一堆后面的猴子也和第1只进行了同样的做法,请问N只猴子进行了同样做法后这一堆桃子至少还剩了多少个桃子(假设剩下的每堆中至少有一个桃子)?而最初时的那堆桃子至少有多少个? 【【文件输入文件输入】】输入包含二个数据,数据间用空格隔开第一个数据为猴子的只数N(1≤N≤10),第二个数据为桃子分成的堆数M(2≤M≤7) 【【文件输出文件输出】】输出包含两行数据,第一行数据为剩下的桃子数,第二行数据为原来的桃子数 【【样例输入样例输入】】3 2 【【样例输出样例输出】】 1 15 (一)递推的应用(一般递推问题)(一)递推的应用(一般递推问题)•【【例题例题6】】传球游戏(传球游戏(NOIP2008普及)普及)•【【问题描述问题描述】】上体育课的时候,小蛮的老师经常带着同学们一起做游戏。

      这次,老师带着同学们一起做传球游戏   游戏规则是这样的:n(3<=n<=30)个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再吹哨子时,传球停止,此时,拿着球没传出去的那个同学就是败者,要给大家表演一个节目   聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m(3<=m<=30)次后,又回到小蛮手里两种传球被视作不同的方法,当且仅当这两种方法中,接到球的同学按照顺序组成的序列是不同的比如3个同学1号、2号、3号,并假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共两种 分析n设f[i,k]表示经过k次传到编号为i的人手中的方案数,传到i号同学的球只能来自于i的左边一个同学和右边一个同学,这两个同学的编号分别是i-1和i+1,所以可以得到以下的递推公式:          f[i,k]=f[i-1,k-1]+f[i+1,k-1]          f[1,k]=f[n,k-1]+f[2,k-1],   当i=1时          f[n,k]=f[n-1,k-1]+f[1,k-1],   当i=n时          边界条件:f[1,0]=1;’没传边界条件          answer=f[1,m]         ‘传送m次后回到自己。

      参考代码 readln(n,m); f[1,0]:=1; for k:=1 to m do begin f[1,k]:=f[2,k-1]+f[n,k-1]; for i:=2 to n-1 do f[i,k]:=f[i-1,k-1]+f[i+1,k-1]; f[n,k]:=f[n-1,k-1]+f[1,k-1]; end; writeln(f[1,m]); (二)递推的应用(组合计数)(二)递推的应用(组合计数)nCatalan数数n例题例题7:凸:凸n边形的三角形剖分边形的三角形剖分n在一个凸n边形中,通过不相交于n边形内部的对角线,把n边形拆分成若干三角形,不同的拆分数目用f(n)表之,f(n)即为Catalan数例如五边形有如下五种拆分方案,故f(5)=5求对于一个任意的凸n边形相应的f(n) 分析:•设f(n)表示凸n边形的拆分方案总数由题目中的要求可知一个凸n边形的任意一条边都必然是一个三角形的一条边,边P1Pn也不例外,再根据“不在同一直线上的三点可以确定一个三角形”,只要在P2,P3,……,Pn-1点中找一个点Pk(1

      个结点能构成不同二叉数的数目问题分析】:         设F(n)为n个结点组成二叉树的数目         容易知道:f(1)=1;f(2)=2,f(3)=5       选定1个结点为根,左子树结点的个数为i,二叉树数目f(i)种;右子树结点数目为n-i-1,二叉树数目f(n-i-1)种,i的可取范围[0,n-1]所以有:   为了计算的方便:约定f(0)=1 【【扩展扩展2】】:出栈序列:出栈序列【【问题描述问题描述】】::N个不同元素按一定的顺序入栈,求不同的个不同元素按一定的顺序入栈,求不同的出栈序列数目出栈序列数目问题分析】设f(n)为n个元素的不同出栈序列数目       容易得出:f(1)=1;f(2)=2       第n个元素可以第i(1<=i<=n)个出栈,前面已出栈有i-1个元素,出栈方法:f(i-1);后面出栈n-i 个元素,出栈方法为:f(n-i)所以有:         初始条件: F(0)=1  (二)递推的应用(组合计数)(二)递推的应用(组合计数)例题例题10:错排问题(经典问题):错排问题(经典问题)nn个数,分别为1~n,排成一个长度为n的排列。

      若每一个数的位置都与数的本身不相等,则称这个排列是一个错排例如,n=3,则错排有2 3 1、3 1 2编写程序,求n的错排个数 分析Ø我们设k个元素的错位全排列的个数记做:f(k)Ø四个元素的错位排列f(4)我们用穷举法可以找到如下9个: (4,3,2,1);(3,4,1,2);(2,1,4,3) (4,3,1,2);(2,4,1,3);(2,3,4,1) (4,1,2,3);(3,4,2,1);(3,1,4,2)Ø它们有什么规律呢? n通过反复的试验,我们发现事实上有两种方式产生错位排列:            A、将k与(1,2,…,k-1)的某一个数互换,其他k-2个数进行错排,这样可以得到(k-1)×f(k-2)个错位排列             B、另一部分是将前k-1个元素的每一个错位排列(有f(k-1)个)中的每一个数与k互换,这样可以得到剩下的(k-1)×f(k-1) 个错位排列n根据加法原理,我们得到求错位排列的递推公式f(k):f(k)=(k-1)*(f(k–1)+f(k–2))分析分析 (二)递推的应用(组合计数)(二)递推的应用(组合计数)例题例题11:编码问题:编码问题n【【问题描述问题描述】】编码工作常被运用于密文或压缩传编码工作常被运用于密文或压缩传输。

      这里我们用一种最简单的编码方式进行编码:输这里我们用一种最简单的编码方式进行编码:把一些有规律的单词编成数字字母表中共有把一些有规律的单词编成数字字母表中共有26个小写字母个小写字母{a,b,c….,z}这些特殊的单词长度不这些特殊的单词长度不超过超过6且字母按照升序排列把所有这样的单词放且字母按照升序排列把所有这样的单词放在一起,按字典顺序排列,一个单词的编码就对在一起,按字典顺序排列,一个单词的编码就对应着它在字典中的位置,例如:应着它在字典中的位置,例如:a-1;b-2;z-26;ab-27;ac-28;你的任务就是对于所给的单词,求出它你的任务就是对于所给的单词,求出它的编码 (二)递推的应用(组合计数)(二)递推的应用(组合计数) 例题例题12::2^k进制数(进制数(NOIP2006)) 见见word文档文档 (三)递推的应用(博弈问题)(三)递推的应用(博弈问题)例例例例题题题题13131313::::走走走走直直直直线线线线棋棋棋棋问问问问题题题题有如下所示的一个编号为1到n的方格: 现由计算机和人进行人机对奕,从1到n,每次可以走k个方格,其中k为集s={a1,a2, a3,....am}中的元素(m<=4),规定谁最先走到第n格为胜,试设计一个人机对奕方案,摸拟整个游戏过程的情况并力求计算机尽量不败。

      12345 … …N-1 N 分析n题设条件:若谁先走到第N格谁将获胜,例如,假设S={1,2},从第N格往前倒推,则走到第N-1格或第N-2格的一方必败,而走到第N-3格者必定获胜,因此在N,S确定后,棋格中每个方格的胜、负或和态(双方都不能到达第N格)都是可以事先确定的将目标格置为必胜态,由后往前倒推每一格的胜负状态,规定在自己所处的当前格后,若对方无论走到哪儿都必定失败,则当前格为胜态,若走后有任一格为胜格,则当前格为输态,否则为和态 分析分析        设1表示必胜态,-1表示必败态,0表示和态或表示无法到达的棋格        例如,设N=10,S={1,2},则可确定其每个棋格的状态如下所示:        而N=10,S={2,3}时,其每格的状态将会如下所示:        有了棋格的状态图后,程序应能判断让谁先走,计算机选择必胜策略或双方和(双方均不能到达目标格)的策略下棋,这样就能保证计算机尽可能不败1 1-1-1-1-11 1-1-1-1-11 1-1-1-1-11 10 0-1-1-1-10 01 10 0-1-1-1-10 01 1 (四)递推的应用(动态规划中的递推)(四)递推的应用(动态规划中的递推)n例题例题14:最小伤害:最小伤害 n把儿站在一个N x N的方阵中最左上角的格子里。

      他可以从一个格子走到它右边和下边的格子里每一个格子都有一个伤害值他想在受伤害最小的情况下走到方阵的最右下角 分析分析nF[i,j]:设走到(i,j) 这格的最小伤害值,a[i][j]表示(i,j)这格的伤害值nF[i,j]=min(f[i-1,j],f[i,j-1])+a[i,j]n边界条件:f[1,1]=a[1,1] f[i,1]=f[i-1,1]+a[i,1](2<=i<=n) f[1,i]=f[1,i-1]+a[1,i](2<=i<=n) Ø见见wordword文档文档例题例题1515::乌龟棋(乌龟棋(NOIP2010NOIP2010提高)提高) 动态规划与递推的关系动态规划与递推的关系n上题实质上是采用动态规划来求解上题实质上是采用动态规划来求解,那么递推与动那么递推与动态规划之间到底是什么关系呢?态规划之间到底是什么关系呢?n我们不妨画个图我们不妨画个图(如下图如下图)而通常人们理解的递而通常人们理解的递推关系就是一般递推关系,故认为动态规划与递推关系就是一般递推关系,故认为动态规划与递推关系是两个各自独立的个体。

      推关系是两个各自独立的个体动态规划一般递推关系递推关系 动态规划与递推的关系动态规划与递推的关系n1、一般递推边界条件很明显,动态规划边界条件比较隐蔽,容易被忽视;n2、一般递推数学性较强,动态规划数学性相对较弱;n3、一般递推一般不划分阶段,动态规划一般有较为明显的阶段; 第三部分第三部分递归策略递归策略 一、递归的概念一、递归的概念n一个函数、过程、概念或数学结构,如果在其定义或说明内部又直接或间接地出现有其本身的引用,则称它们是递归的或者是递归定义的在程序设计中,过程或函数直接或者间接调用自己,就被称为递归调用 二、递归的基本思想二、递归的基本思想 n递归是借助于一个递归工作栈栈来实现;递归递归=递推递推+回归回归;n1.递推:递推:问题向一极推进, 这一过程叫做递推;这一过程相当于压栈压栈n2.回归:回归:问题逐一解决,最后回到原问题,这一过程叫做回归这一过程相当于弹栈弹栈 二、递归的基本思想二、递归的基本思想例题例题1:用递归算法求:用递归算法求n!定义:函数定义:函数定义:函数定义:函数 fact(n)=n!fact(n)=n!fact(n-1)=(n-1)!fact(n-1)=(n-1)!递推方程:递推方程:递推方程:递推方程:fact(n)=n*fact(n-1)fact(n)=n*fact(n-1)边界条件:边界条件:边界条件:边界条件:fact(1)=1fact(1)=1 81下面画出了调用和返回的递归示意图下面画出了调用和返回的递归示意图下面画出了调用和返回的递归示意图下面画出了调用和返回的递归示意图 三、递归的实现三、递归的实现n递归实现的代价是巨大的栈空间的耗费,那是因为过程每向前递推一次,程序将本层的实在变量(值参和变参)、局部变量构成一个“工作记录”压入工作栈的栈顶,只有退出该层递归时,才将这一工作记录从栈顶弹出释放部分空间。

      n由此可以想到,减少每个“工作记录”的大小便可节省部分空间例如某些变参可以转换为全局变量,某些值参可以省略以及过程内部的精简 例题例题2 2:求:求a[1..n]a[1..n]的最大者的最大者有如下过程:有如下过程:Procedure findmax(i:integer;var max:integer);var j:integer;begin max:=a[i]; if i=n then exit else begin findmax(i+1,j); if j>max then max:=j; end;end; n起始状态就是调用起始状态就是调用findmax(1,max),而像上述过程而像上述过程中的变参中的变参max完全可以省略将上述方法修改可得下完全可以省略将上述方法修改可得下面的算法:面的算法:Procedure findmax(i:integer);begin if i=n then exit else begin findmax(i+1); if a[i]>max then max:=a[i]; end;end; n起始状态就是调用起始状态就是调用findmax(1) ,,max为全局为全局变量,同时还减少了一个局部变量的使用。

      尽管变量,同时还减少了一个局部变量的使用尽管这只是一个很简单的例子,在本例中不做精简,这只是一个很简单的例子,在本例中不做精简,程序也还是能通过,但它精简的原则对其它使用程序也还是能通过,但它精简的原则对其它使用递归的程序而言却是同样适用的特别是在递归递归的程序而言却是同样适用的特别是在递归过程出现过程出现堆栈溢出情况时堆栈溢出情况时就应该考虑这一问题就应该考虑这一问题 四、递归的优点与缺点四、递归的优点与缺点n优点:采用递归方法编写的问题解决程序具有结构清晰,可读性强等优点,且递归算法的设计比非递归算法的设计往往要容易一些,所以当问题本身是递归定义的,或者问题所涉及到的数据结构是递归定义的,或者是问题的解决方法是递归形式的时候,往往采用递归算法来解决n缺点:执行的效率很低,尤其在边界条件设置不当的情况下,极有可能陷入死循环或者内存溢出的窘境 五、递归的应用五、递归的应用n 处理递归定义或解决方法为递归方式的问题n 解决搜索问题和组合计数n 实现分治思想n 用于输出动态规划的中间过程 1、递归定义问题、递归定义问题n树结构是由递归定义的因此,在解决与树有关的问题时,常常可以采用递归的方法。

      2、解决搜索问题、解决搜索问题n因为搜索产生的节点成树状结构,所以可以用递归方法解决这类例子很多,如“N皇后”问题,全排列,哈密顿回路,图的可着色性等搜索问题 例题例题3:全排列:全排列 【【问题描述问题描述】】编程列举出编程列举出1、、2、、…、、n的全排列,要的全排列,要求产生的任一个数字序列中不允许出现重复的数字求产生的任一个数字序列中不允许出现重复的数字文件输入文件输入】】输入输入n(1<=n<=9)【【文件输出文件输出】】有有1到到n组成的所有不重复数字的序列,组成的所有不重复数字的序列,每行一个序列每行一个序列 分析分析n我们假设n=3时,如下图:位置1可以放置数字1、2、3;位置2可以放置数字1、2、3;位置3可以放置数字1、2、3,但是当位置1放了数字1后位置2和位置3都不能在放1,因此画树的约束条件是:各位置的数字不能相同 分析分析n我们画“解答树”时,根结点一般是一个空结点,根结点下面的第1、2、3三层分别对应位置1、位置2、位置3,用“╳”标示的分支表示该结点不满足约束条件,不能被扩展出来: procedure f(k:integer) //搜索第搜索第k层结点(向第层结点(向第k个位置放数)个位置放数)begin var i:integer; if k=n+1 then begin for i:=1 to n do write(a[i]);writeln;end // 如果搜索到一条路径,则输出一种解如果搜索到一条路径,则输出一种解 else for i:=1 to n do//每一个结点可以分解出每一个结点可以分解出n个子结点;个子结点; if b[i]=0 then //如果能生成第如果能生成第k层的第层的第i个结点;个结点; begin a[k]:=i; //第第k个位置为数字个位置为数字i;; b[i]:=1; //标记数字标记数字i已用已用 f(k+1); //扩展第扩展第k层的第层的第i个结点个结点(向第向第k+1个位置放数个位置放数) b[i]:=0; //向上回溯,并恢复数据向上回溯,并恢复数据 end;end;n我们用递归过程来描述我们用递归过程来描述我们用递归过程来描述我们用递归过程来描述 “ “解答树解答树解答树解答树” ”的深度优先搜索的深度优先搜索的深度优先搜索的深度优先搜索 3、实现分治思想、实现分治思想n不难发现,在各种时间复杂度为nlogn排序方法中,大都采用了递归的形式。

      n因此无论是归并排序,还是堆排序、快速排序,都存在有分治的思想只要分开处理,就可以采用递归处理其实进行分治,也是一个建树的过程n如下图中归并排序的过程: 例题例题4:表达式求值:表达式求值 u由键盘输入一个算术表达式,该表达式由数字,加(+)、减(-)、乘(*)、求商(/)运算符及小括号组成 u例如:6*(8-1)+(5-(12-7)/5)/2u请编写一个程序,计算输入表达式的值 funtion tree(left,right:integer):integer;funtion tree(left,right:integer):integer;beginbegin var tmp,L1,L2,p:integer; var tmp,L1,L2,p:integer; tmp:=isnum(left,right); tmp:=isnum(left,right); if tmp<>-1 begin tree:=tmp;exit;end;// if tmp<>-1 begin tree:=tmp;exit;end;//返回值返回值返回值返回值 if (st[left]='(')and (poskh(left,right)=right) thenif (st[left]='(')and (poskh(left,right)=right) then tree:=tree(left+1,right-1); tree:=tree(left+1,right-1); // //去掉最外层的括号去掉最外层的括号去掉最外层的括号去掉最外层的括号 p:=findlow(left,right); //p:=findlow(left,right); //找运算级别最低的运算符找运算级别最低的运算符找运算级别最低的运算符找运算级别最低的运算符 L1:=tree(left,p-1); //L1:=tree(left,p-1); //递归左子树递归左子树递归左子树递归左子树 L2:=tree(p+1,right); //L2:=tree(p+1,right); //递归右子树递归右子树递归右子树递归右子树 tree:=cal(L1,st[p],L2);tree:=cal(L1,st[p],L2);end;end; 4、用于输出动态规划的中间过程、用于输出动态规划的中间过程例题例题5:复制书稿:复制书稿 【【问题描述问题描述】】假设有m本书(编号为1,2,…m),想将每本复制一份,m本书的页数可能不同(分别是p1,p2,…pm)。

      任务是将这m本书分给k个抄写员(k<=m),每本书只能分配给一个抄写员进行复制,而每个抄写员所分配到的书必须是连续顺序的 复制工作是同时开始进行的,并且每个抄写员复制的速度都是一样的所以,复制完所有书稿所需时间取决于分配得到最多工作的那个抄写员的复制时间 n试找一个最优分配方案,使分配给每一个抄写员的页数的最大值尽可能小(如存在多个最优方案,输出结果排序最小的一种) 分析分析n该题中m本书是顺序排列的,k个抄写员选择数也是顺序且连续的不管以书的编号,还是以抄写员标号作为参变量划分阶段,都符合策略的最优化原理和无后效性考虑到k<=m,以抄写员编号来划分阶段会方便些 n设f[i,j]为前i个抄写员复制前j本书的最小“页数最大数”S[i]=a[1]+a[2]+…+a[i],则状态转移方程为:nf[i,j]=min{max(f[i-1,k],S[j]-S[k])}(i-1<=k<=j-1)nd[i,j]=k;记录第i个人的最佳位置n边界条件 f[1,i]=S[i] n输出方案,则递归输出;输出方案,则递归输出;procedure Print(i,j:integer)begin if i=1 then begin writeln(1,’ ‘,j);exit;end; Print(i-1,d[i,j]); writeln(d[i,j]+1,’ ‘,j);end 第四部分第四部分归纳策略归纳策略 一、归纳法的基本思想一、归纳法的基本思想 n归纳法的基本思想:归纳法的基本思想:是通过列举少量的特殊情况,经过分析,最后找出一般的关系。

      n从本质上讲,归纳就是通过观察一些简单而特殊的情况,最后总结出有用的结论或解决问题的有效途径 二、归纳法解题二、归纳法解题的过程的过程1.细心的观察;细心的观察;2.丰富的联想;丰富的联想;3.继续尝试;继续尝试;4.总结归纳出结论总结归纳出结论 二、归纳法解题二、归纳法解题的过程的过程n归纳是一种抽象,即从特殊现象中找出一般关系n由于在归纳的过程中不可能对所有的可能情况进行枚举,因而最后得到的结论还只是一种猜测(即归纳假设)所以,严格说来对于归纳假设还必须加以严格的证明 三、归纳策略解题应注意的问题三、归纳策略解题应注意的问题1.从问题的简单具体状态分析入手,目的是去寻求可以推广的一般性规律,因此应考虑简单状态与一般性状态之间的联系2.从简单状态中分析出来的规律特征应能够被验证是正确的,不能想当然或任意地提出猜想,否则归纳出来的结论是错误的,必然导致整个问题的解是错解 四、归纳策略的应用四、归纳策略的应用例题例题1:求前n个自然数的平方之和: S=12+22+32+……+n2 【【分分析析】】这本是一道很简单的题目,但如果能找出S值与n的关系,则此题将更进一步得到简化,由数学证明得知:(12+22+32+…+n2)/(1+2+3+…+n) =(2n+1)/3又由于 1+2+3+…+n=n(n+1)/2,因此得到: 12+22+32+…+n2=n(n+1) (2n+1)/6 但这只是通过总结归纳而得到的一种猜测,是否正确还需证明,对归纳假设的证明通常采用数学归纳法(证略)。

      例题例题2:乘积最大【问题描述】若干个正整数之和为n,其中:n<2000,试求它们乘积的最大值以及该最大值的位数k 【【【【分析分析分析分析】】】】根据数学规律可知,若要使和固定的数的乘积最大,必须使这些数尽可能的多为3,于是可推得以下规律:•当N mod 3=1 时,N可分解为一个4和若干个3的和; •当N mod 3=2 时,N 可分解为一个2和若干个3的和;•当N mod 3=0 时,N 直接分解为若干个3的和 按照这一分解方法,所有因数的乘积必定最大注意注意:因N 的最大值可达2000,乘积将超过长整型数据范围,所以需用高精度运算 例题例题例题例题3 3:极值问题      已知m、n为整数,且满足下列两个条件:         ① m、n∈1,2,…,K,(1≤K≤109)         ② (n 2-mn-m2)2=1       编一程序,由键盘输入K,求一组满足上述两个条件的m、n,并且使m2+n2的值最大例如,若K=1995,则m=987,n=1597,则m、n满足条件,且可使m2+n2的值最大 【【分析分析】】分析小数据会发现:m,n是Fibonacci数列的相邻两项。

      因为:(n2-mn-m2)2 =1 故: (m2+mn-n2 )2=1 又: m2+mn-n2=(m+n)2-mn-2n2 =(m+n)2-(m+n)n-n2 故:(m2+mn-n2)2=[(m+n)2-(m+n)n-n2]2 即:(n2-mn-m2)2=[(m+n)2-(m+n)n-n2]2 【【【【分析分析分析分析】】】】由上述数学变换式可以得出,如果m和n为一组满足条件①和条件②的解,设n’=m+n,m’=n那么n’,m’也是一组满足条件①和条件②的一组解将所有满足条件①和条件②的m和n 按递增顺序排成一个Fibonacci数列 {1,1,2,3,5,8,……} 数列中小于k的最大两个相邻数即为试题所要求的一组m和n算法算法】】利用Fibonacci数列顺推m,n,求出在条件范围内的m,n最大值,此时m2+n2的值最大 例题例题4:士兵排队问题:士兵排队问题 【【问题描述问题描述】】有有N个士兵(个士兵(1<=N<=100),编号依次为编号依次为1,2,...,N。

      队队列训练时,指挥官要把士兵从高到矮排成一行,但指挥官只知道列训练时,指挥官要把士兵从高到矮排成一行,但指挥官只知道“1 比比2 高,高,7 比比 5高高”这样的比较结果如果不能排成一排,则这样的比较结果如果不能排成一排,则输出输出"No answer"文件输入文件输入】】第一行为一个整数第一行为一个整数N((N<=100),表示士兵的个数表示士兵的个数接下来若干行每行两个数接下来若干行每行两个数A和和B,表示,表示A高于高于BA,B属于1属于1..NN)【【文件输出文件输出】】输出文件只有一行为一个合法的排队序列输出文件只有一行为一个合法的排队序列样例输入样例输入】】 4 1 2 2 3 4 2 1 4【【样例输出样例输出】】1 4 2 3 【【思思路路点点拨拨】】由题意可知,所有士兵的身高关系对应一张图,每两个士兵的身高关系对应于一条边;A高于B对应于一条有向边,将B的入度加1,AB这条边称之为A的出边如果有环,显然不能得到排队方案;无环时,每次选入度为0的点,且删除与该点相连的边,再重复上述操作,即可得到士兵的排队方案这种方法称为拓扑排序,能构造出最优解1243 。

      点击阅读更多内容
      手机版 | 川公网安备 51140202000112号 | 经营许可证(蜀ICP备13022795号)
      ©2008-2016 by Sichuan Goldhoe Inc. All Rights Reserved.