Skip to content

动态规划

Dynamic programming

在有限或良基的状态依赖上复用已计算结果的算法设计范式。

条目类型
原则

形式陈述

动态规划把问题写成状态集 S 上的方程或递推:每个 sS 的值只由其直接依赖 pred(s) 的值组合而成,并为无依赖状态给出基例。若依赖关系是有限无环图,就按拓扑序填表;也可从目标状态递归展开并记忆每个已解状态。更一般地,依赖可以由严格关系 给出:若 tpred(s) 时总有 ts,且 是良基的,则可用良基递归确定每个状态值。具体算法还需要目标可达的状态与直接依赖能够有效枚举,否则这个数学定义未必给出有限的求值过程。

优化问题常有

F(s)=optaA(s){c(s,a)+F(T(s,a))},

但计数、可达性、概率传播和字符串识别使用的是相应合并运算,并不需要“最优子结构”。若有 N 个可达状态,每个状态检查至多 T 个转移,则直接实现通常需 O(NT) 时间和 O(N) 存储。

若状态依赖含环,单纯按表格顺序代入已无定义。一种严格的扩展是先给状态值域配备偏序,再把全部状态方程写成单调算子 F,并明确规定要取的解,例如最小不动点 lfp(F);还需为所用迭代证明收敛到该不动点。任意环状递推方程不会因为“可以反复更新”就自动成为动态规划:解可能不存在、不唯一,或更新根本不收敛。

直觉

动态规划先问“未来究竟需要哪些过去信息”,再把这份充分摘要定义为状态。当两条路径得到同一状态时,它们的后续计算便可合并。状态太少会丢失影响未来的信息,太多则把整段历史原样带入。因此核心工作是证明状态充分、转移完备,并给出合法求值顺序。

动态规划状态依赖与填表顺序
例子与边界

动态规划主动识别并合并相同子问题,以状态表或记忆化避免重复计算;回溯法沿选择树枚举候选,并靠可行性或界限剪枝撤销选择。两者可以组合,但“存在递归分支”并不足以构成动态规划。

Fibonacci 递归的调用树重复解同一下标,记忆化后只剩 n 个状态。最长公共子序列用两个前缀长度 (i,j) 作状态,因而有 O(mn) 个子问题。0–1 背包可定义 dp[i,w] 为前 i 件物品在容量 w 下的最大价值;压成一维后必须从大到小更新容量,否则本轮刚写入的值会让同一物品被重复选取。

状态设为“当前价值”却不保留已用容量,通常无法决定背包的后续可行性;反过来,把所有已选集合当作状态虽然充分,却退化为指数枚举。“写出了递推式”只是起点;还必须证明状态确实包含后续所需的全部信息,转移覆盖了所有合法情形,且所选求值规则真能得到指定的解。

推论与应用

记忆化以需求驱动方式解状态,表格法则按依赖顺序主动求值。动态规划可用于 DAG 最短路、序列比对、背包、矩阵链乘、区间问题、树分解、概率模型与有限时域控制。其中计数、概率与可达性例子也说明,动态规划的主体是状态方程的有效求值,而不是优化问题所特有的“最优子结构”。它与分治的分界是是否复用重叠状态,与贪心的分界则是是否保留多种中间可能后再比较。

高级 DP 仍应从状态 DAG 看待,而不是把新技巧当模板名。子集动态规划2n 个子集作为节点,树宽 DP把 bag 边界状态沿树分解传播,Color Coding用随机着色压缩“互异顶点”约束;三者分别以指数状态、结构参数和随机化换可解性。四俄罗斯与字级并行则批量执行一组有限转移,只改善每条边的处理成本,不改变状态依赖正确性。

参考资料
  • Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein, Introduction to Algorithms, 4th ed., MIT Press, 2022,Part III, dynamic programming, state recurrences and reconstruction。
  • Jon Kleinberg and Éva Tardos, Algorithm Design, Pearson, 2005,Ch. 6, dynamic programming and optimal substructure。
关系图谱14 个相邻概念 · 4 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组
分类位置

上位 / 更一般

暂未标注直接上位概念。

下位 / 直接特例

类型化关系