动态规划的基本思想
动态规划是分治思想的延伸,通俗一点就是大事化小,小事化无的艺术。在将大问题化解为小问题的分治过程中,保存对这些小问题已经处理好的结果,并供后面处理更大规模的问题时直接使用这些结果。
动态规划的特点
动态规划具备以下三个特点:
1把原来的问题分解成了几个相似的子问题
2所有的子问题都只需要解决一次
3储存子问题的解
动态规划的本质
动态规划的本质,是对问题状态的定义和状态转移方程的定义(状态以及状态之间的递推关系)
动态规划问题一般从以下四个角度考虑
1状态定义
2状态间的转移方程定义
3状态初始化,确定的值,不以输入的变化而变化,或者是空状态(尽量有意义)
4返回结果
状态定义的要求:定义的状态一定要形成递推关系。
三特点四要素两本质
适用场景
最大值/最小值、可不可行、是不是、方案个数
例一:斐波那契数列
int Fib(int n)
{
if(n<=0)
return 0;
if(n==1 || n==2)
return 1;
return Fib(n-1)+Fib(n-2);
}
n>2时,O(2n)栈溢出,重复计算
状态:F(i)数列dii项的值
递推:F(i)=F(i-1)+F(i-2)
状态初始化:F(1) = F(2) = 1 F(0) = 0
返回结果:F(n)
//动态规划
#include<vector>
int FibDp(int n)
{
if(n<=0)
return 0;
vector<int> fab(n+1,0);
//初始化
fab[0] = 0;
fab[1] = 1;
//状态递推
for(int i = 2; i<=n; i++)
{
//F(i) = F(i-1)+F(i-2)
fab[i] = fab[i-1]+fab[i-2];
}
//返回结果F(n)
return fab[n];
}
上述代码的空间复杂度为O(n),可以优化为O(1)利用三个临时变量来代替数组
例二 变态青蛙跳台阶
状态:F(i),青蛙跳上台阶的方法数
递推:
跳上1阶,2阶,…n阶
跳1阶,还剩n-1 ----> F(n-1)
跳2阶,还剩n-2 ----> F