动态规划

动态规划（英語：Dynamic programming，简称DP）是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的，通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。 动态规划常常适用于有重叠子问题和最优子结构（英语：Optimal substructure）性质的问题，动态规划方法所耗时间往往远少于朴素解法。 动态规划背后的基本思想非常简单。大致上，若要解一个给定问题，我们需要解其不同部分（即子问题），再根据子问题的解以得出原问题的解。 通常许多子问题非常相似，为此动态规划法试图仅仅解决每个子问题一次，从而减少计算量：一旦某个给定子问题的解已经算出，则将其记忆化存储，以便下次需要同一个子问题解之时直接查表。这种做法在重复子问题的数目关于输入的规模呈指數增長时特别有用。 动态规划在查找有很多重叠子问题的情况的最优解时有效。它将问题重新组合成子问题。为了避免多次解决这些子问题，它们的结果都逐渐被计算并被保存，从简单的问题直到整个问题都被解决。因此，动态规划保存递归时的结果，因而不会在解决同样的问题时花费不必要的时间。 动态规划只能应用于有最优子结构的问题。最优子结构的意思是局部最优解能决定全局最优解（对有些问题这个要求并不能完全满足，故有时需要引入一定的近似）。简单地说，问题能够分解成子问题来解决。 最优子结构性质。如果问题的最优解所包含的子问题的解也是最优的，我们就称该问题具有最优子结构性质（即满足最优化原理）。最优子结构性质为动态規劃算法解决问题提供了重要线索。 无后效性。即子问题的解一旦确定，就不再改变，不受在这之后、包含它的更大的问题的求解决策影响。 子问题重叠性质。子问题重叠性质是指在用递归算法自顶向下对问题进行求解时，每次产生的子问题并不总是新问题，有些子问题会被重复计算多次。动态規劃算法正是利用了这种子问题的重叠性质，对每一个子问题只计算一次，然后将其计算结果保存在一个表格中，当再次需要计算已经计算过的子问题时，只是在表格中简单地查看一下结果，从而获得较高的效率，降低了时间复杂度。 包括但不限于切割钢条问题、Floyd最短路问题、最大不下降子序列、矩阵链乘、凸多边形三角剖分、背包问题、最长公共子序列、最优二分搜索树等。 背包问题作为NP完全问题，暂时不存在多项式时间算法。动态规划属于背包问题求解最优解的可行方法之一。此外，求解背包问题最优解还有搜索法等，近似解还有贪心法等，分数背包问题有最优贪心解等。 背包问题具有最优子结构和重叠子问题。动态规划一般用于求解背包问题中的整数背包问题（即每种物品所选的个数必须是整数）。 解整数背包问题： 设有 n {\displaystyle n} 件物品，每件价值记为 P i {\displaystyle P_{i}} ，每件重量记为 W i {\displaystyle W_{i}} ，用一个最大重量为 W {\displaystyle W} 的背包，求装入物品的最大价值。 在总重量不超过W的前提下，我们希望总价格最高。对于 Y ⩽ W {\displaystyle Y\leqslant W} ，我们将在总重量不超过 Y {\displaystyle Y} 的前提下，总价格所能达到的最高值定义为 A ( Y ) {\displaystyle A(Y)} 。 A ( W ) {\displaystyle A(W)} 即为问题的答案。 显然，A(Y)满足： A ( 0 ) = 0 {\displaystyle A(0)=0} A ( Y ) = max { A ( Y − 1 ) , p j + A ( Y − w j ) } {\displaystyle A(Y)=\max\{A(Y-1),p_{j}+A(Y-w_{j})\}} 其中， p j {\displaystyle p_{j}} 为第 j {\displaystyle j} 种物品的价格。 对于特例01背包问题（即每件物品最多放1件，否则不放入）的问题，我们将在总重量不超过Y的前提下，前j种物品的总价格所能达到的最高值定义为A(j, Y)。 A(j, Y)的递推关系为： A(0, Y) = 0 如果wj > Y, A(j, Y) = A(j - 1, Y) 如果wj ≤ Y, A(j, Y) = max { A(j - 1, Y), pj + A(j - 1, Y - wj)} 参考Pascal代码 for i:=1 to n do for v:=totv downto v[i] do f[v]:=max(f[v],f[v-v[i]]+p[i]); writeln(f[totv]); 参考C++代码（不含include和数组声明） #define max(x,y) (x)>(y)?(x):(y) //max宏函数，也可以自己寫或者使用algorithm for(int i=1;i<=n;i++) for (v=totv;v>=v[i];v--) f[v]=max(f[v],f[v-v[i]]+p[i]); printf("%d",f[totv]); //或std::cout<<f[totv]; 术语“动态规划”最初是在1940年代由理查德·贝尔曼用来描述解决问题的过程，在这个过程中，人们需要一个接一个地找到最佳决策。到1953年，他将其精炼成为现代的含义，特别是指将较小的决策问题嵌套在较大的决策中， 并且该领域随后被电气电子工程师学会认可为系统分析和工程学主题。贝尔曼的贡献以贝尔曼方程的名义被铭记，它是动态规划的核心结果，它以递归形式重申了优化问题。 贝尔曼选择了“动态”这个词来捕捉问题的随时间变化的方面，也因为它听起来令人印象深刻。 “规划”一词指的是使用该方法来找到最佳的“程序”，在于军事训练或后勤计划的意义。这种用法与短语“线性规划”和“数学规划”中的用法相同。 术语起源的上述解释是不足的。正如罗素和诺维格在他们的书中提到上述故事时所写的那样：“这不可能完全正确，因为他的第一篇使用这个词（贝尔曼，1952）的论文出现在威尔逊于 1953 年成为国防部长之前。”此外，还有Harold J. Kushner （页面存档备份，存于互联网档案馆）在演讲中的评论，他记得贝尔曼。他在谈到贝尔曼时引用库什纳的话：“另一方面，当我问他同样的问题时，他回答说他试图通过加上动态来超越乔治·伯纳德·丹齐格的线性规划。也许这两种动机都是正确的。” 最长公共子序列 Floyd-Warshall算法 Viterbi算法 Kadane's_algorithm 求解馬可夫決策過程下最佳策略 萊文斯坦距離 S. Dasgupta, C.H. Papadimitriou, and U.V. Vazirani, 'Algorithms', p 173, available at http://www.cs.berkeley.edu/~vazirani/algorithms.html （页面存档备份，存于互联网档案馆） Stuart Dreyfus. "Richard Bellman on the birth of Dynamical Programming". Eddy, S. R. What is Dynamic Programming?. Nature Biotechnology. 2004, 22 (7): 909–910. PMID 15229554. S2CID 5352062. doi:10.1038/nbt0704-909.  Nocedal, J.; Wright, S. J. Numerical Optimization. Springer. 2006: 9. ISBN 9780387303031.  Russell, S.; Norvig, P. Artificial Intelligence: A Modern Approach 3rd. Prentice Hall. 2009. ISBN 978-0-13-207148-2.  Maximum_subarray_problem. [2023-01-18]. （原始内容存档于2023-02-04）.  Richard S. Sutton; Andrew G. Barto. Reinforcement Learning: An Introduction Second Edition. The MIT Press. 2018: 73 [2020-08-22]. （原始内容存档于2022-01-18）.  引文格式1维护：冗余文本 (link)