算法--递推策略

递推法是一种重要的数学方法,在数学的各个领域中都有广泛的运用,也是计算机用于数值计算的一个重要算法。这种算法特点是:一个问题的求解需一系列
的计算,在已知条件和所求问题之间总存在着某种相互联系的关系,在计算时,如果可以找到前后过程之间的数量关系(即递推式),那么,从问题出发逐步推到已
知条件,此种方法叫逆推。无论顺推还是逆推,其关键是要找到递推式。这种处理问题的方法能使复杂运算化为若干步重复的简单运算,充分发挥出计算机擅长于重
复处理的特点。

  递推算法的首要问题是得到相邻的数据项间的关系(即递推关系)。递推算法避开了求通项公式的麻烦,把一个复杂的问题的求解,分解成了连续的若干步简单运算。一般说来,可以将递推算法看成是一种特殊的迭代算法。

引例:Fibonacci数列 

Fibonacci数列的代表问题是由意大利著名数学家Fibonacci于1202年提出的“兔子繁殖问题”(又称“Fibonacci问题”)。

问题:

一个数列的第0项为0,第1项为1,以后每一项都是前两项的和,这个数列就是著名的裴波那契数列,求裴波那契数列的第N项。 

算法:

 f[0]:=0; f[1]:=1;

 for i:=2 to n do f[i]:=f[i–1]+f[i–2];

总结:

从这个问题可以看出,在计算裴波那契数列的每一项目时,都可以由前两项推出。这样,相邻两项之间的变化有一定的规律性,我们可以将这种规律归纳成如下简捷的递推关系式:Fn=g(Fn-1),这就在数的序列中,建立起后项和前项之间的关系。然后从初始条件(或是最终结果)入手,按递推关系式递推,直至求出最终结果(或初始值)。很多问题就是这样逐步求解的。

对一个试题,我们要是能找到后一项与前一项的关系并清楚其起始条件(或最终结果),问题就可以递推了,接下来便是让计算机一步步了。让高速的计算机从事这种重复运算,真正起到“物尽其用”的效果。

递推概念

给定一个数的序列H0,H1,…,Hn,…若存在整数n0,使当n>n0时,可以用等号(或大于号、小于号)将Hn与其前面的某些项Hi(0<i<n)联系起来,这样的式子就叫做递推关系。

  • 如何建立递推关系
  • 递推关系有何性质
  • 如何求解递推关系

解决递推问题的一般步骤

  • 建立递推关系式
  • 确定边界条件
  • 递推求解

递推的两种形式

顺推法和倒推法

递推的应用分类

  • 一般递推问题
  • 组合计数类问题
  • 一类博弈问题的求解
  • 动态规划问题的递推关系

(一)递推的应用(一般递推问题)

例题2:输出杨辉三角的前N行(HDOJ2032

Problem Description

还记得中学时候学过的杨辉三角吗?具体的定义这里不再描述,你可以参考以下的图形:
1
1
1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1

Input

输入数据包含多个测试实例,每个测试实例的输入只包含一个正整数n(1<=n<=30),表示将要输出的杨辉三角的层数。

 

Output

对应于每一个输入,请输出相应层数的杨辉三角,每一层的整数之间用一个空格隔开,每一个杨辉三角后面加一个空行。

 

Sample Input

2 3

Sample Output

1

1 1

 

1

1 1

1 2 1

 

代码如下:

#include <iostream>
using namespace std;
int a[31][31];
int main( )
{
    int i,j,n;
    a[0][0]=a[1][0]=a[1][1]=1;
    for(i=2; i<31; i++) {
        for(j=0; j<=i; j++) {
            if(j==0 || i==j) {
                a[i][j]=1;
            } else {
                a[i][j]=a[i-1][j-1]+a[i-1][j];
            }
        }
    }
    while(cin>>n) {
        for(i=0; i<n; i++) {
            for(j=0; j<=i; j++) {
                if(j!=0) cout<<" ";
                cout<<a[i][j];
            }
            cout<<endl;
        }
        cout<<endl;
    }
    return 0;
}

例题3 : Hanoi塔问题 .

Hanoi塔由n个大小不同的圆盘和三根木柱a,b,c组成。开始时,这n个圆盘由大到小依次套在a柱上,如图1所示。要求把a柱上n个圆盘按下述规则移到c柱上:

(1)一次只能移一个圆盘;

(2)圆盘只能在三个柱上存放;

(3)在移动过程中,不允许大盘压小盘。

问将这n个盘子从a柱移动到c柱上,总计需要移动多少个盘次?

 

分析

当n=1时:A->C

当n=2时:A->B,A->C,B->C

当n=3时:

 

设f(n)为n 个盘子从1柱移到3柱所需移动的最少盘次。

当n=1时,f(1)=1。

当n=2时,f(2)=3。

以此类推,当1柱上有n(n>2)个盘子时,我们可以利用下列步骤:

第一步:先借助3柱把1柱上面的n-1个盘子移动到2柱上,所需的移动次数为f(n-1)。

第二步:然后再把1柱最下面的一个盘子移动到3柱上,只需要1 次盘子。

第三步:再借助1柱把2柱上的n-1个盘子移动到3上,所需的移动次数为f(n-1)。

由以上3步得出总共移动盘子的次数为:f(n-1)+1+ f(n-1)。

所以:f(n)=2f(n-1)+1

         hn=2hn-1+1 =2n-1    边界条件:h1=1

(二)递推的应用(组合计数)

例题4:数的计数

【问题描述】我们要求找出具有下列性质数的个数(包含输入的自然数n),先输入一个自然数n(n≤1000),然后对此自然数按照如下方法进行处理:
1.不作任何处理;
2.在它的左边加上一个自然数,但该自然数不能超过原数的一半;
3.加上数后,继续按此规则进行处理,直到不能再而 自然数为止;

 方法1:用递推

用h[n]表示自然数n所能扩展的数据个数,则:h[1]=1,h[2]=2,h[3]=2,h[4]=4,h[5]=4,h[6]=6,h[7]=6,h[8]=10,h[9]=10。分析上数据,可得递推公式:h[i]=1+h[1]+h[2]+…+h[i/2]。时间复杂度O(n2)。 

方法2:是对方法1的改进。我们定义数组s

     s(x)=h(1)+h(2)+…+h(x),

     h(x)=s(x)-s(x-1)

    此算法的时间复杂度可降到O(n)。

方法3:还是用递推

只要做仔细分析,其实我们还可以得到以下的递推公式:

(1)当i为奇数时,h(i)=h(i-1);

(2) 当i为偶数时,h(i)=h(i-1)+h(i/2);

【例题6】传球游戏

【问题描述】上体育课的时候,小蛮的老师经常带着同学们一起做游戏。这次,老师带着同学们一起做传球游戏。
游戏规则是这样的:n(3<=n<=30)个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹哨子时开始传球,每个同学可以把球传给自己左右的两个同学中的一个(左右任意),当老师再吹哨子时,传球停止,此时,拿着球没传出去的那个同学就是败者,要给大家表演一个节目。

聪明的小蛮提出一个有趣的问题:有多少种不同的传球方法可以使得从小蛮手里开始传的球,传了m(3<=m<=30)次后,又回到小蛮手里。两种传球被视作不同的方法,当且仅当这两种方法中,接到球的同学按照顺序组成的序列是不同的。比如3个同学1号、2号、3号,并假设小蛮为1号,球传了3次回到小蛮手里的方式有1->2->3->1和1->3->2->1,共两种。 

分析:

设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=1时

边界条件:f[1][0]=1;结果在f[1][m]中。

核心代码:

cin>>n>>m;
memset(f,0,sizeof(f));
f[1][0]=1;
for(k=1;k<=m;k++)
{
    f[1][k]=f[2][k-1]+f[n][k-1];
    for(i=2;i<=n-1;i++)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];
}
cout<<f[1][m]<<endl;

(三)递推的应用(组合计数)

Catalan数

定义:Cn=n+2条边的多边形,能被分割成三角形的方案数,例如5边型的分割方案有:

 

如图,有一个正n+2边形。任取一边,从这边的端点开始,依次顺时针给顶点编号为:0,1,2,3,….,n,n+1(所取的边端点编号为:0,n+1)。这样,除线段所在顶点外,还有n个顶点:1,2,3,…,n。我们以该线段为三角形的一条边,另一个顶点为i(1<=i<=n)。 

我们设题意要求的三角形剖分方案数为H(n),即除线段顶点(编号0与n+1)外,还有n个顶点时的三角形剖分方案为H(n)。则以顶点0,i为指定线段(上面还有1,2,…,i-1,共i-1个顶点)的剖分数位H(i-1);以顶点n+1,i为指定线段的剖分数为H(n-i)。根据乘法原理,以0,i,n+1为一剖分三角形的剖分数应为:H(i-1)*H(n-i),i=1,2,…,n,所得的剖分各不相同,根据加法原理则有:

这与Catalan数C(n)的表达式是一致的。故本题答案为H(n)=C(n)。

具体实现时,若直接用上述公式计算,对数字的精度要求较高。可将其化为递推式:

再进行递推计算,并且注意类型的定义要用long long长整型。

(四)递推的应用(博弈问题)

例题:走直线棋问题。

有如下所示的一个编号为1到n的方格:

现由计算机和人进行人机对奕,从1到n,每次可以走k个方格,其中k为集s={a1,a2, a3,....am}中的元素(m<=4),规定谁最先走到第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}时,其每格的状态将会如下所示:

有了棋格的状态图后,程序应能判断让谁先走,计算机选择必胜策略或双方和(双方均不能到达目标格)的策略下棋,就能保证计算机尽可能不败。

(五)递推的应用(动态规划中的递推)

例题:方格取数

在一个n×m的方格中,m为奇数,放置有n×m个数 ,如图,方格中间的下方有一人,此人可按照五个方向前进但不能越出方格,见右下图。人每走过一个方格必须取此方格中的数。要求找到一条从底到顶的路径,使其数相加之和为最大。输出和的最大值。

分析:

我们用坐标(x,y)唯一确定一个点,其中(m,n)表示图的右上角,而人的出发点是,受人前进方向的限制,能直接到达点(x,y)的点只有(x+2,y-1),(x+1,y-1),(x,y-1),(x-1,y-1),(x-2,y-1)。到点(x,y)的路径中和最大的路径必然要从(m/2,0)到(x+2,y-1),(x+1,y-1),(x,y-1),(x-1,y-1),(x-2,y-1)的几条路径中产生,既然要求最优方案,当然要挑一条和最大的路径,关系式如下:

Fx,y= Max{Fx+2,y-1 ,Fx+1,y-1,Fx,y-1,Fx-1,y-1,Fx-2,y-1}+Numx,y

其中Numx,y 表示(x,y) 点上的数字。

边界条件为:

动态规划与递推的关系

上题实质上是采用动态规划来求解,那么与递推动态规划之间到底是什么关系呢?

我们不妨画个图(如下图)。而通常人们理解的递推关系就是一般递推关系,故认为动态规划与递推关系是两个各自独立的个体。

 

1、一般递推边界条件很明显,动态规划边界条件比较隐蔽,容易被忽视

2、一般递推数学性较强,动态规划数学性相对较弱

3、一般递推一般不划分阶段,动态规划一般有较为明显的阶段

时间: 2024-10-02 20:23:46

算法--递推策略的相关文章

算法——递推算法

递推算法 给定一个数的序列H0,H1,-,Hn,-若存在整数n0,使当n>n0时,可以用等号(或大于号.小于号)将Hn与其前面的某些项Hi(0<i<n)联系起来,这样的式子就叫做递推关系. 递推算法是一种简单的算法,即通过已知条件,利用特定关系得出中间推论,直至得到结果的算法.  递推算法分为顺推和逆推两种. 相对于递归算法,递推算法免除了数据进出栈的过程,也就是说,不需要函数不断的向边界值靠拢,而直接从边界出发,直到求出函数值.  比如阶乘函数:f(n)=n*f(n-1)  在f(3)

“大整数阶乘”问题的递推算法

/* 标题:<<系统设计师>>应试编程实例-[递推算法程序设计] 作者:成晓旭 时间:2002年09月11日(11:52:00-16:26:00) 实现递推算法的大整数阶乘处理函数 时间:2002年09月16日(18:38:00-20:02:00) 实现"斐波那契数列"问题的递推算法函数 */ //:============================"大整数阶乘"问题的递推算法=========================== #d

UVa 10049 Self-describing Sequence:自描述序列&amp;amp;二分递推

10049 - Self-describing Sequence Time limit: 3.000 seconds http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=34&page=show_problem&problem=990 Solomon Golomb's self­describing sequence is the only non­decreasing

UVa 10519 !! Really Strange !! (递推)

10519 - !! Really Strange !! Time limit: 3.000 seconds http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=115&page=show_problem&problem=1460 思路:注意到题目所说"Every two area have exactly two points to intersect and

c++问题-递推 数的划分问题一

问题描述 递推 数的划分问题一 把正整数N分解成M个正整数的和,即使M个数相同但顺序不同也认为是不同的方案,要求总方案数.如3=1+2跟3=2+1是两个不同的方案

递推求解专题练习

hdoj2044--一只小蜜蜂... Problem Description 有一只经过训练的蜜蜂只能爬向右侧相邻的蜂房,不能反向爬行.请编程计算蜜蜂从蜂房a爬到蜂房b的可能路线数. 其中,蜂房的结构如下所示.   Input 输入数据的第一行是一个整数N,表示测试实例的个数,然后是N 行数据,每行包含两个整数a和b(0<a<b<50). Output 对于每个测试实例,请输出蜜蜂从蜂房a爬到蜂房b的可能路线数,每个实例的输出占一行. Sample Input 2 1 2 3 6 Sam

POJ2229 递推

这题明显递推 但是找了好久才找出来 很明显的是n为奇数的时候 n=n-1的偶数答案一样 n为偶数的时候 答案为 上一个偶数是情况 +1 +1 还有n/2 的情况同一 *2 所以h[n]=h[n-2]+h[n/2] #include <iostream> #include<cstdio> #include<cstring> using namespace std; int d[1000005]; int main() { d[1]=1; d[2]=2; for(int i

互联网设计瀑布递推

中介交易 http://www.aliyun.com/zixun/aggregation/6858.html">SEO诊断 淘宝客 云主机 技术大厅 递推流程有明显的阶段划分僵化劣势,优点缺点显而易见: 适合技术较弱或缺乏经验的设计团队. 适合容易理解但很复杂的产品,易于组织和管理. 适合稳定的产品定义和很容易被理解的设计解决方案. 适合对产品规模的升级和架构扩展,质量容易保证. 与软件工程思想并无二致,基于以上特点,递推流程尤其不适合互联网产品的创新设计.虽然经过江湖前辈的努力总结提炼,

网易游戏调整地推策略:重点转向校园及IT卖场

网易副总裁陈伟安(腾讯科技配图)腾讯科技讯(雷建平)9月28日消息,网易副总裁陈伟安昨日就网易游戏策略与腾讯科技展开交流.陈伟安透露,网易业绩在下一个季度将超速增长,不过<魔兽世界>新资料片<大灾变>及暴雪旗下游戏<星际争霸2>上线暂无时间表.陈伟安也承认在地推策略上进行了调整,称以前地推可能更多的是关注网吧,现在则将很大一部分精力转向了高校.IT卖场.各游戏工作室单独运营据了解,<天下贰>是一款由网易历时6年,投资过亿研发的绿色免费3D网游,此前曾多次回炉