动态规划
动态规划解题的基本思路
1.如果问题是求一个问题的最优解(通常是求最大值或最小值),而且该问题能够分解成若干个子问题,并且子问题之间还有重叠的更小的子问题,就可以考虑用动态规划来解决这个问题。
在应用动态规划之前要分析能否把大问题分解为小问题,分解之后的每个小问题也存在最优解。如果把小问题的最优解组合起来能够得到整个问题的最优解,那么我们就可以应用动态规划来解决这个问题。
动态规划问题的三个特点:
1.求一个问题的最优解
2.整体问题的最优解依赖于各个子问题的最优解。
3.这些子问题之间还有相互重叠的更小的子问题。
4.自上到下分析问题,自底向上求解问题。
由于子问题在分解大问题的过程中重复出现,为了避免重复求解子问题。所以我们可以用自底向上的顺序先计算小问题的最优解并存储下来(一维或二维数组里),再以此为基础求取大问题的最优解。
能够灵活运用动态规划解决问题的关键是具备从上到下分析问题,从下到上解决问题的能力。
动态规划基础
1.最优子结构
动态规划以自底向上的方式来利用最优子结构,首先找到子问题的最优解,解决子问题,然后找到问题的一个最优解。问题解的代价通常是子问题的代价加上选择本身带来的开销。
贪心算法也适用于具有最优子结构的问题,而与动态规划问题有着明显的区别就是在贪心算法中,是以自底向下的方式使用最优子结构的。贪心算法会先做在当前看起来是最优的选择,然后再求解一个结果子问题,而不是先寻找子问题的最优解,然后再做选择。
子问题独立:一个子问题的解不会影响同一问题中另外一个子问题的解。
2.重叠子问题
适用于动态规划求解的最优化问题必须具有的第二个要素是子问题的空间要很小,也就是用来解原问题的递归算法可反复地解同样的子问题,而不是总在产生新的子问题。
当一个递归算法不断地调用同一问题时,我们说该最优问题包含重叠子问题。
相反的,适用于分治法解决的问题往往在递归的每一步都产生全新的问题。
动态规划算法总是充分利用重叠子问题,即通过每个子问题只解一次,把解保存在一个需要时就可以查看的表中,而每次查表的时间为常数。
相比于自顶向下的递归算法和自底向上的动态规划算法作个比较,可以看出后者更加有效,因为它利用了重叠子问题的性质。而递归算法对递归树中重复出现的每个子问题都要重复解一次。
3.做备忘录
动态规划有一种变形,它既具有通常的动态规划的效率,又采用了一种自顶向下的策略。其思想就是备忘原问题的自然且低效的递归算法。
加了备忘的递归算法为每一个子问题的解在表中记录一个表项。开始时,每个表项最初都包含一个特殊的值,以表示该表项有待输入。当在递归算法的执行中第一个遇到一个子问题时,就计算它的值并填入表中。以后再次遇到时,只要查看并返回表中先前填入的值即可。
在实际应用中,如果所有的子问题都至少要被计算一次,则一个自底向上的动态规划算法通常要比一个自顶向下的做备忘录算法好出一个常数因子,因为前者无需递归的代价,而且维护表格的开销也小些。