【动态规划】题目1:跳台阶

题目1:跳台阶

一个楼梯共有 n 级台阶,每次可以走一级或者两级,问从第 0
级台阶走到第 n 级台阶一共有多少种方案。

输入格式
共一行,包含一个整数 n。

输出格式
共一行,包含一个整数,表示方案数。

数据范围
1 ≤ n ≤ 15 1 \le n \le 15 1n15

解题思路

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 向下递归的公式
  • 递推数组的初始值 = 递归的边界
  • 13
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值