递推与递归

提示:递推与递归是算法设计的基础,难到floyed,简单到快排,都可以用递归和递推来进行设计。

一、递推是什么?

递推就是通过一层一层的推理,来推得最后结果的算法。

可能在奥数上,这只能解决小部分数据小的问题。

但是——

计算机比人脑更快,更不嫌烦!

于是超级有用的动态规划就有效的利用了这个思想。

写不出状态转移方程的话还是暴搜吧


二、递归是什么?

让我们先知道递归这种结构——

请翻开《信息学奥赛一本通(C++版)》第127页,我们便有了个定义:

调用自身的函数称为递归函数。

那么我们就可以利用递归,将大问题逐渐分成几个小问题再合并来求解。

顺便一提,利用递归,我们就可以巧(zuo)妙(si)地设计一个死循环:

#include<bits/stdc++.h>
using namespace std;
int main(){
    main();
}

从这个例子我们也可以得到一个结论:

主程序也可以递归。

三、常见例题

1.数塔问题(递推,搬运自《信息学奥赛一本通(C++版)》第211页)

P1216 [USACO1.5][IOI1994]数字三角形 Number Triangles

其实在洛谷上这是一道dp题,并且在《信息学奥赛一本通(C++版)》的基础算法的第9章动态规划中的确又提到了这个问题(但是换了更典型的样例),但是——

dp中的状态转移方程不就是递推式吗?

于是呢就让我们来打个表(就是手动模拟思路,从表中寻找方程的意思):

我们令a[i][j]来存储金字塔中第i行第j个数,就可以这么存:

a12345
17
238
3810
42744
545265

我们就可以把金字塔存下来了,我们再令f[i][j]为加至第i行第j个所得到的最大值,于是又有下表:

f12345
17=a[1][1]+max(f[0][0],f[0][1])
210=a[2][1]+max(f[1][0],f[1][1])15=a[2][2]+max(f[1][1],f[1][2])
318=a[3][1]+max(f[2][0],f[2][1])16=a[3][2]+max(f[2][1],f[2][2])15=a[3][3]+max(f[2][2],f[2][3])
420=a[4][1]+max(f[3][0],f[3][1])25=a[4][2]+max(f[3][1],f[3][2])20=a[4][3]+max(f[4][2],f[4][3])19=a[4][4]+max(f[3][3],f[3][4])
524=a[5][1]+max(f[4][0],f[4][1])30=a[5][2]+max(f[4][1],f[4][2])27=a[5][3]+max(f[4][2],f[4][3])26=a[5][4]+max(f[4][3],f[4][4])24=a[5][5]+max(f[4][4],f[4][5])

由上表我们可以知道几个接下来程序设计的重要信息:

1.状态转移方程:

f[i][j]=a[i][j]+max(f[i-1][j-1],f[i-1][j])

1<=i<=r

1<=j<=i

2.边界值(下两种边界均可行):

(1)f[1][1]=a[1][1]

(2)对于1<=i<=r,1<=j<=i时,有f[i][j]=0

3.答案为f[r]中的最大值

于是AC代码如下(1号边界自己想,我就不写了):

#include<bits/stdc++.h>
#define max(a,b)(a>b?a:b)
using namespace std;
int r,a[1001][1001],f[1001][1001],ans;
int main(){
	scanf("%d",&r);
	for(int i=1;i<=r;i++)for(int j=1;j<=i;j++)scanf("%d",&a[i][j]);
	for(int i=1;i<=r;i++)for(int j=1;j<=i;j++)f[i][j]=a[i][j]+max(f[i-1][j-1],f[i-1][j]);
	for(int i=1;i<=r;i++)ans=max(ans,f[r][i]);
	printf("%d",ans);
}

时间复杂度为O(n^2)

2.数列求和

我们又双叒叕可以打个表(但是这次程序得用递归实现):

令f(x)为加至x的最大值,于是有下表:

代码如下(示例):

012345
01=f(0)+13=f(1)+26=f(2)+310=f(3)+415=f(4)+5

由上表我们可得:

f(x)=f(x-1)+x

边界:f(0)=0

AC代码如下:

#include<bits/stdc++.h>
using namespace std;
int n;
int f(int x){
    if(x==0)return 0;
    return f(x-1)+x;
}
int main(){
    scanf("%d",&n);
    printf("%d",f(n));
}

时间复杂度为O(n)


总结

1.递推通过逐步推理推出结果;

2.递归通过自身调用求出结果。

顺便说句题外话,今后我们学到的深度优先搜索(简称深搜,字母表示为dfs)利用了深搜的思想;动态规划则利用了递推的思想。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值