递推算法

递推简介

一个问题的求解需一系列的计算,在已知条件和所求问题之间总存在着某种相互联系的关系,如果可以找到前后过程之间的数量关系(即递推式),那么,从问题出发逐步推到已知条件,此种方法叫逆推。无论顺推还是逆推,其关键是要找到递推式以及边界条件

递推相关问题

以下所有代码均用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;
  }

总结:递推是一种正向解决问题的方法,解决递推问题的关键是找到递推公式终止条件,从而可以利用循环解决问题。递推有顺推和逆推两种,要根据实际问题选择合适的,提高解决问题的效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值