递归和递推

recursion

递归和递推

递归

  • 从问题的最终目标出发,逐渐将复杂问题化为简单问题,最终求得问题。是逆向的

递推

  • 从简单问题出发,一步步的向前发展,最终求得问题。是正向的。

差别

  • 递归中问题的n 要求是计算之前就知道。而递推可以在计算中确定,不要求计算前就知道n 。

  • 从程序上看,递归表现为自己调用自己,递推则没有这样的形式。

  • 一般来说,递推的效率高于递归(当然是递推可以计算的情况下)

  • 递归调用函数,浪费空间,并且递归太深容易造成堆栈的溢出

一般用递归考虑问题,然后用非递归方式编写。

例题讲解

猴子吃桃

原题链接

题目描述

猴子吃桃子问题:猴子第一天摘下若干个桃子,当即吃了一半还不过瘾,又多吃了一个;第二天又将剩下的桃子吃掉一半又多吃了一个;以后每天早上都吃了前一天剩下的一半零一个。到了第十天想再吃时,见只剩下一个桃子,求第一天共摘了多少个桃子?

输入

输出

一个整数,第一天共有多少个桃子。

answer

通过递归思路求得第一天为n个桃,之后每一天吃一半加一个,当第十天的时候则剩只一个,共经过9天为9次,后一天都是前一天 x/2 - 1 个,则前一天都是后一天 (x+1) * 2 个,为 2x + 2 个。

理清思路用递推来编写则为,一个变量x初始为1,经过9次计算 2x + 2 得到最终答案第一天的桃子数

1
2
3
4
5
6
7
8
9
10
11
12
#include<iostream>
using namespace std;

int main(){
int x=1;

for(int i=1;i<10;i++){
x=x*2+2;
}

cout<<x<<endl;
}

过河卒

原题链接

answer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<iostream>
using namespace std;

int main(){
int n,m,x,y;
cin>>n>>m>>x>>y;

// 初始化棋盘
int arr[n+1][m+1];
for (int i = 0; i < n+1; i++) {
for (int j = 0; j < m+1; j++) {
arr[i][j]=0;
}
}

// 建立马的控制点
arr[x][y]=-1;
if(y>=1 && x>=2) arr[x-2][y-1]=-1;
if(y>=1 && x<=n-2) arr[x+2][y-1]=-1;
if(y>=2 && x>=1) arr[x-1][y-2]=-1;
if(y>=2 && x<=n-1) arr[x+1][y-2]=-1;
if(y<=m-1 && x>=2) arr[x-2][y+1]=-1;
if(y<=m-1 && x<=n-2) arr[x+2][y+1]=-1;
if(y<=m-2 && x>=1) arr[x-1][y+2]=-1;
if(y<=m-2 && x<=n-1) arr[x+1][y+2]=-1;

// 递推统计每一格可达的路径数
arr[0][0]=1;
for (int i = 0; i < n+1; i++) {
for (int j = 0; j < m+1; j++) {
if(arr[i][j]==-1){
continue;
}
if(i>=1){
if(arr[i-1][j]!=-1){
arr[i][j]+=arr[i-1][j];
}
}
if(j>=1){
if(arr[i][j-1]!=-1){
arr[i][j]+=arr[i][j-1];
}
}
}
}

cout<<arr[n][m]<<endl;
}