入门——动态规划

点击查看代码
/*
动态规划

第一种:通过记忆化搜素(先用递归的思想去解决问题;如果有重复子问题,就改成用记忆化搜索的形式)

(其实递推形式的动态规划中的各种表述,是可以对应到递归形式的:
• 状态表⽰ <---> 递归函数的意义;
• 状态转移⽅程 <---> 递归函数的主函数体;
• 初始化 <---> 递归函数的递归出⼝。)


第二种:直接使用递推形式的动态规划解决:
1.定义状态表示:
        一般情况下根据经验+递归函数的意义,赋予dp数组相应的含义
2.推导状态转移方程:
        根据状态表示以及题意,在dp表中分析,当前格子如何通过其余各自推导出来
3.初始化:
        根据题意,先将显而易见的以及边界情况下的位置填上值
4.确定填表顺序:
        根据状态转移方程,确定按照什么顺序来填表
5.确定最终结果
        根据题意,在表中找出最终结果
*/


/*
题目:下楼梯

1.状态表示:
        经验/题意
        f[i]表示:有i个台阶的时候,一共有多少种方案

2.状态转移方程
        (重点****)根据“最后一步”的情况,来推导状态转移方程
        ·····
        f[i] = f[i-1] + f[i-2] + f[i-3]
3.初始化:
        1.保证填表是正确的
        2.填表的时候不越界

4.填表顺序:从左到右
5.最终结果:f[n]

6.优化:空间优化
        滚动数组:
        一维 -> 若干变量   o(n) -> o(1) 空间
        二维 -> 一维       o(n^2) -> o(n)

    滚动数组很少能对时间做优化
    《背包问题》 --- 重点使用空间优化(可同步实现时间优化)
*/


#include <iostream>  // 引入输入输出流头文件,用于cin/cout
typedef long long LL; // 定义长整型别名LL,避免溢出(n较大时结果会超过int范围)
using namespace std;  // 使用std命名空间,简化cin/cout的书写

const int N = 70;     // 定义常量N=70,限制台阶数的最大值
//LL dp[N];             // 定义dp数组,dp[i]表示走到第i级台阶的总走法数

int main(){
    int n;
    cin >> n;         // 输入台阶数n
    
    // //版本一:用数组的形式
    // // 初始化边界条件(动态规划的"初始状态")
    // dp[1] = 1;        // 1级台阶:只有1种走法(走1级)
    // dp[2] = 2;        // 2级台阶:2种走法(1+1 或 2)
    // dp[3] = 4;        // 3级台阶:4种走法(1+1+1、1+2、2+1、3)
    
    // // 状态转移:递推计算dp[i]
    // for(int i = 4; i <= n; i++){
    //     // 核心逻辑:走到第i级的走法数 = 走到i-1级(最后走1级) + 
    //     // 走到i-2级(最后走2级) + 走到i-3级(最后走3级)
    //     dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
    // }
    
    // cout << dp[n] << endl; // 输出第n级台阶的总走法数

    //版本二:空间优化
    LL a = 1, b = 1, c = 2; //通过三个变量便可以一直保存下一级楼梯的所有走法
    for(int i = 3; i <= n ; i++){
        LL t = a + b + c; // t表示到当前楼梯的所有走法
        //“滚动数组”,向右滚动
        a = b;
        b = c;
        c = t; //c便是最后第i级的所有走法
    }
    if(n == 1) cout << b << endl;//n == 1时,不会进入循环
    cout << c << endl;

    return 0;
}
posted @ 2026-03-10 21:18  无酒无剑  阅读(13)  评论(0)    收藏  举报