一、什么是动态规划
动态规划,Dynamic Programming(“Programming”为“规划”,而非指“程序”、“编程”),研究多步决策过程最优化问题的一种数学方法,英文缩写DP。在动态规划中,为了寻找一个问题的最优解(即最优决策过程),将整个问题划分成若干个相应的阶段,并在每个阶段都根据先前所作出的决策作出当前阶段最优决策,进而得出整个问题的最优解。
二、什么样的题能使用动态规划
1、最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。
2、无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。
3、有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(虽不是必要条件,但如果没有这条性质,动态规划算法同其他算法相比就不具备优势)
三、一般解题思路
1、拆分问题
2、 定义状态(并找出初状态)
3、 状态转移方程
四、两种动态规划的方法
1、自顶而下的备忘录法
利用meno数组来存放斐波拉契数列中的每一个值,由于是自顶往下递归,它还是会最先递归到meno[3],从此刻开始在往上计算,然后依次保存计算结果在meno数组中,避免了重复运算。
int Fibonacci(int n)
{
if(n <= 0)
return 0;
int meno[n + 1];
for(int i = 0; i <= n; i++)
meno[i] = -1;
return fib(n, meno);
}
int fib(int n, int *meno)
{
if(meno[n] != -1)
return meno[n];
if(n <= 2)
meno[n] = 1;
else
meno[n] = fib(n - 1, meno) + fib(n - 2, meno);
return meno[n];
}
2、自顶而下的方式
这样计算最终的结果,还是有一个递归的过程。既然最终是从fib(1)开始算,那么直接从fib(1)计算不就得了,先算子问题,再算父问题。
int fib(int n)
{
if(n <= 0)
return n;
int meno[n + 1];
meno[0] = 0
meno[1] = 1;
for(int i = 2; i <= n; i++)
meno[i] = meno[i - 1] + meno[i - 2];
return meno[n];
}
还可以再优化:
对空间进行压缩
int fib(int n)
{
if(n <= 1)
return n;
int meno_i_1 = 0;
int meno_i_2 = 1;
int meno_i = 1;
for(int i = 2; i <= n; i++)
{
meno_i = meno_i_1 + meno_i_2;
meno_i_2 = meno_i_1;
meno_i_1 = meno_i;
}
return meno_i;
}