[[TOC]]
教学目标
- 使用小朋法来分解问题
- 理解递归的分支
- 理解递归是在树上的行走
题目
题目描述
斐波那契数列
输入
一个整数
输出
斐波那契数列的第
示例
输入:
5
输出:
5
小朋友法
想像,有一个小朋友他的问题为:求斐波那契数列的第
加入有一个问题为
上面的图形有形状很像是一个倒过来的树,最上面的点
代码
#include <iostream>
using namespace std;
int fibonacci(int n) {
if( n ==1 || n ==2 )
return 1;
return fibonacci(n-1) + fibonacci(n-2);
}
int main() {
int n;
cin >> n;
int ans = fibonacci(n);
cout << ans;
return 0;
}
代码理解
如何理解代码的运行过程呢?
请同学们使用磊方块法,在纸上模拟整个过程.
TODO:动画
一边磊方块,一边栈顶的函数
- 递归前进: 就是从树上的父亲到孩子
- 递归回溯: 就是从树上的孩子到父亲
记忆化
上面的代码的运行过程中有很多重复的过程,比如
可以想到
#include <iostream>
using namespace std;
const int maxn = 1e5+5;
int f[maxn];
int fibonacci(int n) {
if( n ==1 || n ==2 )
return 1;
//如果f[n]的值不是0,表明已经得到值了
// 直接返回
if( f[n] != 0) return f[n];
// 重新计算,并返回
f[n] = fibonacci(n-1) + fibonacci(n-2);
return f[n];
}
int main() {
int n;
cin >> n;
int ans = fibonacci(n);
cout << ans;
return 0;
}
新的代码的时间复杂度是
总结
通过这个题目,我们学会了
分解子问题
你有一个问题B_1,B_2,\cdots,B_n来解A可以拆分成子问题B_1,B_2,\cdots,B_n
且子问题B_i与原问题A是相似的,只是规模变小了,那么显然子问题B_i也可以拆分,直到边界
前进就是分解子问题
回溯就是子问题得到解,回到原问题A时
递归本质就是树上行走
题目
- luogu P1255 数楼梯