算法——递推

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

论顺推还是逆推,其关键是要找到递推式。这种处理问题的方法能使复杂运算化为若干步重复的简单运算,充分发挥出计算机擅长于重复处理的特点。
递推算法的首要问题是得到相邻的数据项间的关系(即递推关系)。递推算法避开了求通项公式的麻烦,把一个复杂的问题的求解,分解成了连续的若干步简单运算。一般说来,可以将递推算法看成是一种特殊的迭代算法。
【例1】如下所示为一个数字三角形。请编一个程序计算从顶到底的某处的一条路径,使该路径所经过的数字总和最大。只要求输出总和。
1、 一步可沿左斜线向下或右斜线向下走;
2、 三角形行数小于等于100;
3、 三角形中的数字为0,1,…,99;
在这里插入图片描述

测试数据通过键盘逐行输入,如上例数据应以如下所示格式输入:
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
【算法分析】
  此题解法有多种,从递推的思想出发,设想,当从顶层沿某条路径走到第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] 即为所求的数字总和的最大值。

【参考程序】
此题的关键是以下三角存储数据
#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; 
}

【例2】满足F1=F2=1,Fn=Fn-1+Fn-2的数列称为斐波那契数列(Fibonacci),它的前若干项是1,1,2,3,5,8,13,21,34……求此数 列第n项(n>=3)。
即:f1=1 (n=1)
f2=1 (n=2)
fn=fn-1 + fn-2 (n>=3)

程序如下:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
    int f0=1,f1=1,f2;
    int n;
    cin>>n;
 	for (int i=3; i<=n; ++i)
    {
         f2=f0+f1;
         f0=f1;
         f1=f2;
    }
	cout<<f2<<endl;
	return 0;
} 

有关Fibonacci数列的问题:楼梯有n个台阶,上楼可以一步上一阶,也可以一步上两阶。一共有多少种上楼的方法?
这是一道计数问题。在没有思路时,不妨试着找规律。n=5时,一共有8种方法:
5=1+1+1+1+1
5=2+1+1+1
5=1+2+1+1
5=1+1+2+1
5=1+1+1+2
5=2+2+1
5=2+1+2
5=1+2+2
  其中有5种方法第1步走了1阶,3种方法第1步走了2阶,没有其他可能。假设f(n)为n个台阶的走法总数,把n个台阶的走法分成两类。
  第1类:第1步走1阶,剩下还有n-1阶要走,有f(n-1)种方法。
  第2类:第1步走2阶,剩下还有n-2阶要走,有f(n-2)种方法。
得到了递推式:f(n)=f(n-1)+f(n-2),不要忘记边界情况:f(1)=1,f(2)=2。把f(n)的前几项列出:1,2,3,5,8,……。

程序如下:
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
    int f0=1,f1=1,f2;
    int n;
    cin>>n;
 	for (int i=3; i<=n; ++i)
    {
         f2=f0+f1;
         f0=f1;
         f1=f2;
    }
	cout<<f2<<endl;
	return 0;
} 

【例3】把雌雄各一的一对新兔子放入养殖场中。每只雌兔在出生两个月以后,每月产雌雄各一的一对新兔子。试问第n个月后养殖场中共有多少对兔子。
还是先找找规律。
  第1个月:一对新兔子r1。用小写字母表示新兔子。
  第2个月:还是一对新兔子,不过已经长大,具备生育能力了,用大写字母R1表示。
  第3个月:R1生了一对新兔子r2,一共2对。
  第4个月:R1又生一对新兔子r3,一共3对。另外,r2长大了,变成R。
  第5个月:R1和R2各生一对,记为r4和r5,共5对。此外,r3长成R3。
  第6个月:R1、R2和R3各生一对,记为r6~r8,共8对。此外,r4和r5长大。
……
  把这些数排列起来:1,1,2,3,5,8,……,事实上,可以直接推导出来递推关系f(n)=f(n-1)+f(n-2):第n个月的兔子由两部分组成,一部分是上个月就有的老兔子f(n-1),一部分是上个月出生的新兔子f(n-2)(第n-1个月时具有生育能力的兔子数就等于第n-2个月兔子总数)。根据加法原理,f(n)=f(n-1)+f(n-2)。

程序如下:
#include<iostream>
#include<cstdio>
using namespace std;
int fun(int n)
{
	if(n<=2) return 1;
	else return fun(n-1)+fun(n-2);
}
int main()
{
    int n;
    cin>>n;
	cout<<fun(n)<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值