动态规划就要从 DAG 聊起: 我们之前 (有向图中的 DFS)中提到过 DAG 的线性化,DP 的问题实际上就是在这样一个有拓扑排序的 DAG 上进行的,比如计算距离:

LIS

最经典的一个问题!我们需要求最长上升子序列

通过大小关系建有向边实际上就把问题变成了 DAG 上的最长路径。于是有简单的算法 以这个为例子,DP 的本质是子问题的解决之间的转移

似乎只是为了介绍 DP 的想法,故没有讲更 technical 的内容了(如 的算法)

编辑差距 Edit Distance

这里的情境可以考虑一个电子词典机(我年纪小的时候还是有这个东西的)或者拼写检查器,或者单纯的输入法联想也可以。对于模糊单词和联想单词的距离的测度问题,我们想到的比较理想的距离为编辑距离,即最好条件下修改前者的字母变为后者的修改次数

比如 抽象为下面两个集合之间的距离

转移公式的来源是寻找子问题,而不重不漏(不过这里只需要多种情况取最优,不漏就行啦)的一种好办法是分类讨论。我们可以考虑最后一步是改 / 删 A / 删 B,于是得到转移公式

Knapsack 背包问题

这个问题(包括下面的矩阵链)由于讲过,就略写了

无限背包问题(可重复)

直接对最后一个分类讨论,容易知道是

0-1 背包

需要分二维变为 ,分最后一个取不取 得到 也是

矩阵链乘法

希望找到最优的相乘顺序,使用中间的相乘间隔分类讨论,作区间 DP 即可

TSP 旅行商问题

TSP 问题,即对 个顶点,希望找到一个路径最短的 tour。这是一个 NP 难问题(判定有没有路径长度小于等于 的问题则是一个 问题,优化问题不一定 NP 哦)

注:关于 TSP 问题,一般的 TSP 问题目前是不可近似的!(除非 P = NP),不过如果边权满足三角不等式(e.g. 边权就是欧几里得长度),则已经有算法可以得到略小于 的近似比,欧几里得长度下则有更好的结果,请见 Travelling salesman problem - Wikipedia 以进一步了解

暴力显然是 ,下面考虑 DP 做法:分开讨论起点,随后对终点进行分类讨论 每个这样的子问题需要 ,而子问题最多有 个(前一个 是不同起点,后面的 是子集数)

综上,得到了一个 的算法

树中独立集

一般图中的最大独立集是 的,但在树中却可以线性时间解决 只需要分取不取 root 就可以了,每个顶点只会用到常数次(parent 和 grandparent 都是固定的),所以一共就是