一般 DP 转移方程

· · 算法·理论

动态规划(DynamIc ProgrammIng,或称 DP)算法通常用于全局求解某种具有最优性质的问题。\ 动态规划算法与分治法类似,其基本思想也是将待求解的问题分解成若干个子问题,先求解子问题,然后从这些子问题的解中得到原有问题的解。与分治法不同的是,动态规划经分解后得到的子问题往往不是相互独立 的

1. 常见的线性 DP(LInear DP)

这应该是最简单的 DP 模型了。这个模型用于解决所有呈线性的状态转移的 DP。 :::Info[符号说明]

${Dp}$ = 动态规划状态数组;\ ${AsLth}$ = 所求子序列长度;\ ${SeqThIs}$ = 原始序列(索引从 ${0}$ 开始);\ ${SeqOthr}$ = 其他序列(同理,在 LCS 等会用到); :::: ### 1.1 LIS 最长上升子序列 **一般性的问题**:求序列中严格递增的最长子序列长度(元素不要求连续)。\ **状态定义**:${Dp[I]}$ 表示以第 ${I}$ 个元素结尾的**最长上升子序列长度**。\ **转移方程**: ${Dp[I] = \max\limits_{\substack{0 \leq J < I \\ SeqThIs[J] < SeqThIs[I]}} \{ Dp[J] \} + 1}$\ **初始值**: ${Dp[I] = 1 \quad (\forall 0 \leq I < SqLth)}$\ **结果**: ${AsLth = \max\limits_{0 \leq K < SqLth} Dp[K]}

1.2 LNDS 最长不降子序列

一般性的问题:求序列中非递减的最长子序列(允许相等元素)。\ 状态定义{Dp[I]} 表示以第 {I} 个元素结尾的最长不降子序列长度。\ 转移方程

**初始值**: ${Dp[I] = 1 \quad (\forall 0 \leq I < SqLth)}$\ **结果**: ${AsLth = \max\limits_{0 \leq K < SqLth} Dp[K]}

1.3 LNIS 最长不升子序列

一般性的问题:求序列中非递增的最长子序列(允许相等元素)。\ 状态定义{Dp[I]} 表示以第 {I} 个元素结尾的最长不升子序列长度。\ 转移方程

**初始值**: ${Dp[I] = 1 \quad (\forall 0 \leq I < SqLth)}$\ **结果**: ${AsLth = \max\limits_{0 \leq K < SqLth} Dp[K]}

1.4 LCS 最长公共子序列

一般性的问题:求两个序列的最长公共子序列(元素不要求连续)。\ 状态定义{Dp[I][J]} 表示序列 A 前 {I} 个元素与序列 B 前 {J} 个元素的最长公共子序列长度。\ 转移方程{Dp[I][J] = \begin{cases} Dp[I-1][J-1] + 1 & SeqThIs[I-1] = SeqOthr[J-1] \\ \max(Dp[I-1][J], Dp[I][J-1]) & SeqThIs[I-1] \neq SeqOthr[J-1] \end{cases}}\ 初始值{ \begin{cases} Dp[I][0] = 0 & \forall 0 \leq I \leq SqLth_A \\ Dp[0][J] = 0 & \forall 0 \leq J \leq SqLth_B \end{cases}}\ 结果

{AsLth = Dp[SqLth_A][SqLth_B]}

2. 常见的背包 DP(Knapsack DP)

也是最常见的 DP 模型,用于解决贪心不能解决的在有限容量下选择物品以获得最优的问题。(下列叙述将仅叙述其特征!) :::Info[符号说明]

${Dp}$ = 动态规划状态数组;\ ${V_{T}}$ = 第 ${T}$ 件物品的价值;\ ${M_{T}}$ = 第 ${T}$ 件物品的重量(代价);\ ${C_{T}}$ = 第 ${T}$ 件物品的数量; :::: ### 2.1 01 背包 特征要素: + 每件物品只有 ${1}$ 样 --- 那么考虑:设 ${Dp[I][J]}$ 表示**选择(单样或不选)前 ${I}$ 个物品在占用不超过 ${J}$ 容量时的最大的价值**。\ 思路:考虑打擂台(选最优嘛)。 1. 选第 ${I}$ 件物品,则此时的 ${Dp[I][J]=Dp[I-1][J-W_{I}]+V_{I}}$; 2. 不选,就是 ${Dp[I][J]}$。 此时,状态转移方程就是: ${ Dp[I][J]=\max \begin{cases} Dp[I][J],\\ Dp[I-1][J-M_{I}]+V_{I} \end{cases} }

实现时需要注意:逆推 + 滚动数组会更优!

2.2 ON 背包(完全背包)

::::success[题外话] 0N 背包是因为机房里有很多人喜欢写这样子的代码:

const Int N=0x7f7f7f7f;

而这个数很大,可以说是无穷大(对于 Int 来说)。而完全背包又刚刚好对应的下面的要素。 :::: 特征要素: