递推简介
一个问题的求解需一系列的计算,在已知条件和所求问题之间总存在着某种相互联系的关系,如果可以找到前后过程之间的数量关系(即递推式),那么,从问题出发逐步推到已知条件,此种方法叫逆推。无论顺推还是逆推,其关键是要找到递推式以及边界条件
递推相关问题
以下所有代码均用C++编写
1 . 求菲波那契数列的前 n 项
Fibonacci 数列:0,1,1,2,3,5,8,13,21,34,……
f0 = 0
f1 = 1
fn = fn-1 + fn-2 ( n >= 2 )
分析: 递推式已经给出,直接由递推式可得结果
int n, a0, a1 ;
cin >> n ;
a0 = 0 ; a1 = 1 ;//递推初始数据
for (int i = 2; i <= n/2 ; i ++ ){//for循环依次递推
a0 = a0 + a1 ;
a1 = a1 + a0 ;
cout << a0 << " "<< a1 << " ";
}
2. 求 N 层汉诺塔的移动次数
在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置N个金盘。把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。
分析 :此问题可以采用逆推的方式解决,当A上只有一个的时候,B上
有n-1个,从A到C需要移动一次,B到C则成为了n-1层汉诺塔的问题。可以得出递推式:f(n)=2f(n-1)-1;
边界条件:一个汉诺塔的时候需要移动一次即:f(1)=1;
int f[1000]={0,1};//递推边界
int n;
cin>>n;
for(int i=2;i<=n;i++)
f[i]=2*f[i-1]+1;//递推式
cout<<f[n]<<endl;
3.猴子吃桃
猴子第一天采摘了一些桃子,第二天吃了第一天的一半多一个,第三天吃了第二天的一半多一个…直到第十天就剩下一个。问:猴子第一天摘了多少桃子?
分析:容易得到边界条件:f(10)=1;每次后一天都是吃了前一天的一半多一个 逆向分析 第九天=(第十天+1)*2 ; 第八天=(第九天+1)*2;
由此可得递推式 f(n-1)=(f(n)+1)*2;
int a[11];
a[10]=1;
for(int i=9;i>=1;i--)
a[i]=2*(a[i+1]+1);
cout<<a[1]<<endl;//求的是第一天的桃子个数
4.数字三角形
一个程序计算从顶到底的某处的一条路径,使该路径所经过的数字总和最大。只要求输出总和。
1、 一步可沿左斜线向下或右斜线向下走;
2、 三角形行数小于等于100;
3、 三角形中的数字为0,1,…,99;
分析:顺推法:从顶层到底层
从(1,1)出发到最底层路径最大权值和,路径中是各个点串联而成,路径起点固定,终点和中间点相对不固定。可以定义F[x][y] 表示从(1,1)出发到达(x,y)的 路径最大权值和。
采用二维数组B[x][y]来存储数据可以得出边界条件:F[1][1]=B[1][1];
到下一层有两种方向:
向左:F[x-1][y]+B[x][y];
向右:F[x-1][y-1]+B[x][y];
最终取所有到达最后一层的最大值:
Ans=max{F[N][1],F[N][2],…,F[N][N]}。
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX = 2000;
int B[MAX][MAX],F[MAX][MAX],N;
int main() {
cin >> N; //输入层数
for(int i = 1;i <= N;i ++)
for(int j = 1;j <= i;j ++)
cin >> B[i][j];//输入数据
F[1][1] = B[1][1]; //边界条件
for(int i = 2;i <= N;i ++)
for(int j = 1;j <= i;j ++)
F[i][j]=max(F[i-1][j-1],F[i-1][j])+B[i][j];
int ans =0;
for(int i = 1;i <= N;i ++)
ans = max(ans,F[N][i]);
cout << ans << endl;
return 0;
}
逆推法:从底层到顶层 存储方式相同
定义F[x][y] 表示 从n层出发到达(x,y)的路径最大权值和
从底层开始,本身数即为最大数;以后每一层都和下一层数据有关
易得递推 边界条件: F[n][i]=B[n][i]
到上一层有两种方式:
向左:F[i+1][j]+B[i][j];
向右:F[i+1][j+1]+B[i][j];
最后取最大值:
F[i][j]=max(F[i+1][j],F[i+1][j+1])+B[i][j];
#include <iostream>
#include <algorithm>
using namespace std;
const int MAX = 2000;
int B[MAX][MAX],F[MAX][MAX],N;
int main() {
int i; cin >> N;
for( i = 1;i <= N;i ++)
for(int j = 1;j <= i;j ++)
cin >> B[i][j];
for( i = 1;i <= N;i ++)
F[N][i] = B[N][i];
for( i = N-1;i >=1;i --)
for(int j = 1;j <= i;j ++)
F[i][j]=max(F[i+1][j],F[i+1][j+1])+B[i][j];
cout << F[1][1] << endl;
return 0;
}
总结:递推是一种正向解决问题的方法,解决递推问题的关键是找到递推公式和终止条件,从而可以利用循环解决问题。递推有顺推和逆推两种,要根据实际问题选择合适的,提高解决问题的效率。