如果原问题是由交叠的子问题构成(递归调用),动态规划对每个子问题只求解一次,并把结果记录在表中,递推计算得到原始问题的解。
它是只求一次子问题,所以相比于递归暴力求解就复杂度降低了
但相对于记忆化搜索,时间复杂度是一样的,只是记忆化搜索需要用到递归,是一种“从顶到底”的方法,而动态规划是一种“从底到顶”的方法。
动态规划为什么叫做动态规划,就是因为当前你需要做决策,而当前的决策会需要选择不同的以前的最优决策,这个规划是动态的。
解题步骤
可分为多个相关子问题,子问题的解可以被重复使用(下方例子中是 F 数组与 value 数组来保留子问题解的),这也是相比于递归暴力求解效率提高的关键,下方前两个例子会简单比较效率,第二个例子由于数据不具代表性,所以有所差异
动态规划的关键就是如何根据条件从上一个子问题的最优解到该现状的途径(写出递推关系)
然后该途径会有很多种再根据问题通过 min 或 max 求得哎现状的最优解,该现状当然也又有可能出现在之后现状的子问题当中
写出初始条件
(之前自己理解的误区)在理解中不要仅仅注意到递推关系,比如背包问题中之前理解错了是总是感觉包括第 i 件物品的组合肯定肯定比不包括第 i 件物品的组合的总价值大,这种理解的错法在于没有真正理解到动态规划的自下而上,而仅仅看到了递推关系,实际上这里 F(i ,j),变的不仅仅是 i,还有 j,相当于你不包括第 i 件物品,那么你就有更多的空间去选择其他的,总之就是包含第 i 件与不包含第 i 件的前一子组合的子组合是不同的。
求斐波拉契数列:
给定一排硬币,这些整数不一定两两相同,使得在其原始位置互不相邻的条件下,所选的硬币金额最大
包括最后一枚的:c_n + F(n-2)
不包括最后一枚的:F(n-1)
m 种币值,找零金额为 n,求最少使用多少枚币
获取 n 的途径只能是:在总金额为$n-d_j$的一堆硬币加入一个面值为$d_j$的硬币,其中$j=1,2,...,m,$并且$n \geq d_j$。因此我们只需考虑所有满足上述要求的$d_j$并选择使得$F(n-d_j)+1$最小的$d_j$即可。由于 1 是常量,我们显然可以先找出最小的$F(n-d_j)$,然后加 1 即可,公式: $$ \left {\begin{matrix} F(n)= \underset{j:n \geq d_j}{min} { F(n-d_j) }+1& n>0\ F(0)=0 & \end{matrix}\right. $$
两者的时间复杂度是一样的,只是记忆化搜索需要用到递归。
注意,这里代码容易迷惑的地方就是:
value[i - 1][j]
代表的就是前一项,dp表默认填充了0;w[i - 1]
和v[i - 1]
代表的是当前项,这里的i
是从 1 开始的,所以要减去 1。TODO
TODO
TODO
TODO
TODO
TODO