点击查看代码
/*
动态规划
第一种:通过记忆化搜素(先用递归的思想去解决问题;如果有重复子问题,就改成用记忆化搜索的形式)
(其实递推形式的动态规划中的各种表述,是可以对应到递归形式的:
• 状态表⽰ <---> 递归函数的意义;
• 状态转移⽅程 <---> 递归函数的主函数体;
• 初始化 <---> 递归函数的递归出⼝。)
第二种:直接使用递推形式的动态规划解决:
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;
}