题目1:跳台阶
一个楼梯共有 n 级台阶,每次可以走一级或者两级,问从第 0
级台阶走到第 n 级台阶一共有多少种方案。
输入格式
共一行,包含一个整数 n。
输出格式
共一行,包含一个整数,表示方案数。
数据范围
1
≤
n
≤
15
1 \le n \le 15
1≤n≤15
解题思路
1.递归
input:5
由于一次只能走一级或两级台阶,因此5级台阶的走法分为:走3级台阶再走一次(2级)、4级台阶再走一次(1级)。即5级台阶的走法等于3级台阶走法和4级台阶走法之和。以此类推,可以画出dfs树:
叶子结点只存在两种情况:
1:只能走1步
→
\rightarrow
→ 1种情况
2:一次走2步or走两个1步
→
\rightarrow
→ 2种情况
代码实现
#include <iostream>
using namespace std;
int dfs(int x)
{
if (x == 1)return 1;
if (x == 2)return 2;
return dfs(x - 1) + dfs(x - 2);
}
int main()
{
int x;
cin >> x;
cout << dfs(x) << endl;
return 0;
}
2.递归+记忆化搜索
继续前面的分析,我们根据题目条件绘制出了DFS树后,得到了问题最基本的解法。然而,这种算法存在着很多重复计算,例如3这颗子树。
记忆化搜索的目的是将已经计算过的子树结果存储在一个数组中,当下次遇到时无需递归计算,直接访问数组便可以得到答案。
代码实现(记忆化搜索标准模板)
#include <iostream>
using namespace std;
int mem[100];
int dfs(int x)
{
if (mem[x])return mem[x];
int sum = 0;
if (x == 1)sum = 1;
else if (x == 2)sum = 2;
else sum = dfs(x - 1) + dfs(x - 2);
mem[x] = sum;
return mem[x];
}
int main()
{
int x;
cin >> x;
cout << dfs(x) << endl;
return 0;
}
总结–递归的过程
- "递” 的过程是分解子问题的过程(自顶向下)
- "归” 的过程才是产生答案的过程(自底向上)
3.递推(DP)–自底向上寻找答案
代码实现
#include <iostream>
using namespace std;
int f[100];
int main()
{
int x;
cin >> x;
f[1] = 1, f[2] = 2;
for (size_t i = 3; i <= x; i++)
{
f[i] = f[i - 1] + f[i - 2];
}
cout << f[x] << endl;
return 0;
}
一种更节省空间的写法
#include <iostream>
using namespace std;
int main()
{
int x;
cin >> x;
if (x==1)
{
cout << "1" << endl;
return 0;
}
else if (x == 2)
{
cout << "2" << endl;
return 0;
}
int tmp1 = 1, tmp2 = 2, newf = 0;
for (size_t i = 3; i <= x; i++)
{
newf = tmp1 + tmp2;
tmp1 = tmp2;
tmp2 = newf;
}
cout << newf << endl;
return 0;
}
最暴力的 d f s → 记忆化搜索 → 递推 ( d p ) 最暴力的dfs \rightarrow 记忆化搜索 \rightarrow 递推(dp) 最暴力的dfs→记忆化搜索→递推(dp)
- 记忆化搜索 = 暴力dfs + 记录答案
- 递推的公式 = dfs 向下递归的公式
- 递推数组的初始值 = 递归的边界