动态规划

+ 感觉要写好久.. 但确实考的很多

动态规划问题

1. 数字三角形模型

状态表示:f[i, j] 所有从起点走到(i, j)的路径中数字和最大值

f[i, j] = max(f[i - 1, j - 1] + a[i, j], f[i - 1, j - 1])

2. 序列问题

2.1 最长上升子序列问题

状态表示:f[i], 以i结尾的序列长度

记录方案:额外开一个数组 保存转移的过程

o(nlogn)版本:

最小值一定是单调递增的,所以对于最长子序列而言,只用在每种长度有一个结尾更小的;

因此找到最大的 小于a_i的书 直接更新最小值 a_i+1

2.2 最长公共子序列

状态表示:f[i, j]表示第一个字符串从0-i, 第二个字符串从0-j,无需以当前元素结尾;

f[i, j ] = max(f[i - 1][j], f[i][j - 1], f[i - 1][j - 1] + 1);

2.3 编辑距离

2.4 正则表达式匹配

2.5 高楼扔鸡蛋

状态表示:f[i, j] 用j个鸡蛋,尝试i次可以得到的最高高度

f[i, j] = f[i - 1, j] + 1 + f[i - 1, j - 1]

3. 背包问题合集

3.1 0-1背包问题

状态表示:f[i, j]表示只能从前i个物品里选,总体积 <= j的方案

优化:只用到j - vi 一维数组 从右向左更新

3.2 完全背包问题

除了遍历顺序是从左到右,剩下和0-1背包问题完全一致

3.3 多重背包问题

优化方式:二进制打包优化;

3.4 分组背包问题

问题:分组,每组只能选一个 因此多了一个遍历组的过程 -> 组内0/1背包

3.5 背包问题求具体方案

f[i, j] = max(f[i - 1, j], f[i - 1, j - v[i]] + w[i]);

最后输出f[n, m]

其实是判断每个物品是否备选,倒退出来再这个状态转移方程中,选择是的第一项还是第二项

具体区别:

  1. 不能用状态压缩的方式 -> 两维状态循环无所谓

  2. 判断f[n][m]倒退,判断是否从上一状态转移过来

0-1背包问题求方案: (字典序最小-> 贪心的选(可选可不选,因为字典序最小,就要选)

3.6 背包问题求方案数

最优解的方案数 -> 有点像路径条数

f[i, j]

新开一个g[i, j] f[i, j] 取最大值的方案数

分三种情况:

  • f[i - 1, j] 大 g[i - 1][j]

  • f[i - 1, j - v[i]] + w[i] 大, g[i - 1, j - v[i]]

  • 相等:两个想加

-> 可以用一维来写

4. 状态机模型

5. 状态压缩DP

6. 区间DP

7. 树形DP

8. 数位DP

9. 单调队列优化的DP问题

Last updated