第3章 信奥递推算法(C++版)

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
min{m , n}1 i 0
s 1=
(n i ) * (m i )
2.长方形和正方形的个数之和s 宽为1的长方形和正方形有m个,宽为2Baidu Nhomakorabea长方形和正方形有 m-1个,┉┉,宽为m的长方形和正方形有1个; 长为1的长方形和正方形有n个,长为2的长方形和正方形有n1个,┉┉,长为n的长方形和正方形有1个; 根据乘法原理
下面是输入n,输出x1~xn的c++程序: #include<iostream> using namespace std; int main() { int n,i,j,a[101]; cout<<"input n:"; //输入骨牌数 cin>>n; a[1]=1;a[2]=2; cout<<"x[1]="<<a[1]<<endl; cout<<"x[2]="<<a[2]<<endl; for (i=3;i<=n;i++) //递推过程 { a[i]=a[i-1]+a[i-2]; cout<<"x["<<i<<"]="<<a[i]<<endl; } } 下面是运行程序输入 n=30,输出的结果: input n: 30 x[1]=1 x[2]=2 x[3]=3 ........ x[29]=832040 x[30]=1346269
【例5】位数问题 【问题描述】 在所有的N位数中,有多少个数中有偶数个数字3?由于结果可能很大, 你只需要输出这个答案对12345取余的值。 【输入格式】 读入一个数N 【输出格式】 输出有多少个数中有偶数个数字3。 【输入样例】 2 【输出样例】 73 【数据规模】 1<=N<=1000 【样例说明】 在所有的2位数字,包含0个3的数有72个,包含2个3的数有1个,共73 个
【算法分析】 方法一:排列组合(但需要运用动态规划)。 可以列出公式,在n个格子中放x个3(其中x为偶数,包括0).。 c(n,x)*9^(n-x)-c(n-1,x)*9^(n-x-1) 含义为在n个格子中取x个3,且不考虑第 一位的特殊情况为c(n,x)*9^(n-x)。 而第一位为0的情况,为c(n-1,x)*9^(n-x-1),两者减下,就为答案。 方法二:递推 考虑这种题目,一般来说都是从第i-1位推导第i位,且当前位是取偶数还是 取奇数的。 恍然大悟.可以用f[i][0]表示前i位取偶数个3有几种情况,f[i][1]表示前i位取 奇数个3有几种情况。 则状态转移方程可以表示为: f[i][0]=f[i-1][0]*9+f[i-1][1];f[i][1]=f[i-1][0]+f[i-1][1]*9; 边界条件:f[1][1]=1;f[1][0]=9;
【例3】棋盘格数
设有一个N*M方格的棋盘( l≤ N≤100,1≤M≤100)。求出该棋盘中包含有多少 个正方形、多少个长方形(不包括正方形)。 例如:当 N=2, M=3时: 正方形的个数有8个:即边长为1的正方形有6个;边长为2的正方形有2个。 长方形的个数有10个:即2*1的长方形有4个:1*2的长方形有3个:3*1的长 方形有2个:3*2的长方形有1个: 程序要求:输入:N,M 输出:正方形的个数与长方形的个数 如上例:输入:2 3 输出:8 10 【算法分析】 1.计算正方形的个数s1 边长为1的正方形个数为n*m 边长为2的正方形个数为(n-1)*(m-1) 边长为3的正方形个数为(n-2)*(m-2) ………… 边长为min{n,m}的正方形个数为(m-min{n,m}+1)*(n-min{n,m}+1) 根据加法原理得出
【参考程序】 #include<iostream> using namespace std; int main() { int n,i,j,a[101][101]; cin>>n; for (i=1;i<=n;i++) for (j=1;j<=i;j++) cin>>a[i][j]; //输入数字三角形的值 for (i=n-1;i>=1;i--) for (j=1;j<=i;j++) { if (a[i+1][j]>=a[i+1][j+1]) a[i][j]+=a[i+1][j]; //路径选择 else a[i][j]+=a[i+1][j+1]; } cout<<a[1][1]<<endl; }
【例1】数字三角形。如下所示为一个数字三角形。请编一个程序计算从顶到 底的某处的一条路径,使该路径所经过的数字总和最大。只要求输出总和。 1、 一步可沿左斜线向下或右斜线向下走; 2、 三角形行数小于等于100; 3、 三角形中的数字为0,1,…,99; 测试数据通过键盘逐行输入,如上例数据应以如下所示格式输入: 5 7 38 810 2744 45265 【算法分析】 此题解法有多种,从递推的思想出发,设想,当从顶层沿某条路径走到第i 层向第i+1层前进时,我们的选择一定是沿其下两条可行路径中最大数字的方向 前进,为此,我们可以采用倒推的手法,设a[i][j]存放从i,j 出发到达n层的最大 值,则a[i][j]=max{a[i][j]+a[i+1][j],a[i][j]+a[i+1][j+1]},a[1][1] 即为所求的数字总 和的最大值。
第三章 递推算法
递推法是一种重要的数学方法,在数学的各个领域中都 有广泛的运用,也是计算机用于数值计算的一个重要算法。 这种算法特点是:一个问题的求解需一系列的计算,在已知 条件和所求问题之间总存在着某种相互联系的关系,在计算 时,如果可以找到前后过程之间的数量关系(即递推式), 那么,从问题出发逐步推到已知条件,此种方法叫逆推。无 论顺推还是逆推,其关键是要找到递推式。这种处理问题的 方法能使复杂运算化为若干步重复的简单运算,充分发挥出 计算机擅长于重复处理的特点。 递推算法的首要问题是得到相邻的数据项间的关系(即 递推关系)。递推算法避开了求通项公式的麻烦,把一个复 杂的问题的求解,分解成了连续的若干步简单运算。一般说 来,可以将递推算法看成是一种特殊的迭代算法。
【算法分析】 跳马是一道老得不能再老的题目,我想每位编程初学者都学过,可能是 在学回溯或搜索等算法的时候,很多书上也有类似的题目,一些比赛中也 出现过这一问题的变形(如NOIP1997初中组的第三题)。有些同学一看 到这条题目就去搜索,即使你编程调试全通过了,运行时你也会发现:当 n,m=15就会超时。 其实,本题稍加分析就能发现,要到达棋盘上的一个点,只能从左边过 来(我们称之为左点)或是从上面过来(我们称之为上点),所以根据加 法原理,到达某一点的路径数目,就等于到达其相邻的上点和左点的路径 数目之和,因此我们可以使用逐列(或逐行)递推的方法来求出从起点到 终点的路径数目。障碍点(马的控制点)也完全适用,只要将到达该点的 路径数目设置为0即可。 用F[i][j]表示到达点(i,j)的路径数目,g[i][j]表示点(i, j)有无障碍,g[i][j]=0 表示无障碍,g[i][j]=1表示有障碍。 则,递推关系式如下: F[i][j] = F[i-1][j] + F[i][j-1] //i>0且j>0且g[i][j]= 0 递推边界有4个: F[i][j] = 0 //g[i][j] = 1 F[i][0] = F[i-1][0] //i > 0且g[i][0] = 0 F[0][j] = F[0][j-1] //j > 0且g[0][j] = 0 F[0][0] = 1 考虑到最大情况下:n=20,m=20,路径条数可能会超过231-1,所以要用 高精度。
【参考程序】 #include<iostream> using namespace std; int main() { long long a[101]={0},b[101]={0},i,j,x,y,z; cin>>x>>y>>z; for(i=1;i<=x;i++){a[i]=1;b[i]=0;} for(i=x+1;i<=z+1;i++) //因为要统计到第z个月后,所以要for到z+1 { b[i]=y*a[i-x]; a[i]=a[i-1]+b[i-2]; } cout<<a[z+1]<<endl; return 0; }
【例6】过河卒(Noip2002) 【问题描述】 棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向 下、或者向右。同时在棋盘上的任一点有一个对方的马(如C点),该马 所在的点和所有跳跃一步可达的点称为对方马的控制点,如图3-1中的C点 和P1,„„,P8,卒不能通过对方马的控制点。棋盘用坐标表示,A点 (0,0)、B点(n, m) (n,m为不超过20的整数),同样马的位置坐标是需要给 出的,C≠A且C≠B。现在要求你计算出卒从A点能够到达B点的路径的条数。
(4)当n=3时:骨牌可以全部竖排,也可以认为在方格中已经有一个竖排 骨牌,则需要在方格中排列两个横排骨牌(无重复方法),若已经在方格中排 列两个横排骨牌,则必须在方格中排列一个竖排骨牌。如上右图,再无其他排 列方法,因此铺法总数表示为x3=3。 由此可以看出,当n=3时的排列骨牌的方法数是n=1和n=2排列方法数的 和。 (5)推出一般规律:对一般的n,要求xn可以这样来考虑,若第一个骨牌是 竖排列放置,剩下有n-1个骨牌需要排列,这时排列方法数为xn-1;若第一个骨 牌是横排列,整个方格至少有2个骨牌是横排列(1*2骨牌),因此剩下n-2个 骨牌需要排列,这是骨牌排列方法数为xn-2。从第一骨牌排列方法考虑,只有 这两种可能,所以有: xn=xn-1+xn-2 (n>2) x1=1 x2=2 xn=xn-1+xn-2就是问题求解的递推公式。任给n都可以从中获得解答。例如n=5, x3=x2+x1=3 x4=x3+x2=5 x5=x4+x3=8
【参考程序】 #include<iostream> using namespace std; int main() { int f[1001][2],n,i,x; cin>>n; f[1][1]=1;f[1][0]=9; for(i=2;i<=n;i++) { x=f[1][0]; if(i==n)x--; f[i][0]=(f[i-1][0]*x+f[i-1][1])%12345; f[i][1]=(f[i-1][1]*x+f[i-1][0])%12345; } cout<<f[n][0]; return 0; }
(1 n) * (1 m) * n * m s=(1+2+┉┉+n)*( 1+2+┉┉+m)= 4
3.长宽不等的长方形个数s2 显然,s2=s-s1
(1 n) * (1 m) * n * m min{m,n}1 = - (n i ) * (m i ) 4 i 0
由此得出算法: #include<iostream> using namespace std; int main() { int n,m; cin>>m>>n; int m1=m,n1=n,s1=m*n; while (m1!=0&&n1!=0) { m1--;n1--; s1+=m1*n1; } int s2=((m+1)*(n+1)*m*n)/4-s1; cout<<s1<<" "<<s2<<endl; }
【例2】 有 2χn的一个长方形方格,用一个1*2的骨牌铺满方格。
编写一个程序,试对给出的任意一个n(n>0), 输出铺法总数。 【算法分析】 (1)面对上述问题,如果思考方法不恰当,要想获得问题的解 答是相当困难的。可以用递推方法归纳出问题解的一般规律。 (2)当n=1时,只能是一种铺法,铺法总数有示为x1=1。 (3)当n=2时:骨牌可以两个并列竖排,也可以并列横排,再 无其他方法,如下左图所示,因此,铺法总数表示为x2=2;
//计算正方形的个数s1
// 计算长方形的个数s2
【例4】昆虫繁殖 【问题描述】 科学家在热带森林中发现了一种特殊的昆虫,这种昆虫的繁殖能力很强。 每对成虫过x个月产y对卵,每对卵要过两个月长成成虫。假设每个成虫 不死,第一个月只有一对成虫,且卵长成成虫后的第一个月不产卵(过X 个月产卵),问过Z个月以后,共有成虫多少对? 0=<X<=20,1<=Y<=20,X=<Z<=50 【输入格式】 x,y,z的数值 【输出格式】 过Z个月以后,共有成虫对数 【输入样例】 128 【输出样例】 37
相关文档
最新文档