做题板子
-
解答模板
- 定义子问题
- 定义目标
- 写递归式与初始化条件
- 伪代码
- 分析时间复杂度
-
1维子问题:
- 输入: x [ 1... n ] x[1...n] x[1...n]序列,字符串,数组
- 子问题: x [ 1... i ] / x [ i . . . n ] x[1...i]/x[i...n] x[1...i]/x[i...n]前缀或后缀
- 复杂度: Θ ( n ) \Theta(n) Θ(n)
- 应用:
- 杆切割?
- 最长递增子序列?
- 上限子数组?
-
2维子问题
- 输入:
x
[
1...
n
]
,
y
[
1...
m
]
x[1...n],y[1...m]
x[1...n],y[1...m]
- 子问题: x [ 1... i ] , y [ 1... j ] x[1...i],y[1...j] x[1...i],y[1...j]
- 复杂度: Θ ( m n ) \Theta(mn) Θ(mn)
- 应用:编辑距离,最长公共子序列
- 输入:
x
[
1...
n
]
x[1...n]
x[1...n]
- 子问题: x [ i . . . j ] x[i...j] x[i...j]
- 复杂度: Θ ( n 2 ) \Theta(n^2) Θ(n2)(不一定)
- 应用:最优二叉查找树,矩阵连乘
- 输入:
x
[
1...
n
]
,
y
[
1...
m
]
x[1...n],y[1...m]
x[1...n],y[1...m]
-
3维子问题
- d ( i , j , k ) = m i n ( d ( i , j , k − 1 ) , d ( i , k , k − 1 ) + d ( k , j , k − 1 ) ) d(i, j, k) = min (d(i, j, k − 1), d(i, k, k − 1) + d(k, j, k − 1)) d(i,j,k)=min(d(i,j,k−1),d(i,k,k−1)+d(k,j,k−1))
-
图上的DP:
- 在DAG上:拓扑序后转换为1D问题(DAG最短路)
- 其他树:左右子树递归
-
背包问题:取/不取的问题
例子
-
最长公共子序列
- 输入: x [ 1... n ] , y [ 1... m ] x[1...n],y[1...m] x[1...n],y[1...m]
- 定义子问题: r [ i , j ] r[i,j] r[i,j]是 x [ 1... i ] 与 y [ 1... j ] x[1...i]与y[1...j] x[1...i]与y[1...j]的最长公共子序列(长度)
- 目标:求出r[n,m]
- 初始化: r [ 0 , j ] = 0 ; r [ i , 0 ] = 0 ; r[0,j]=0;r[i,0]=0; r[0,j]=0;r[i,0]=0;
- 递归式:
r [ i , j ] = { r [ i − 1 , j − 1 ] + 1 , x [ i ] = y [ j ] m a x ( r [ i − 1 , j ] , r [ i , j − 1 ] ) , x [ i ] ! = y [ j ] r[i,j]=\begin{cases} r[i-1,j-1]+1,\quad\quad\quad\quad\quad x[i]=y[j] \\\\ max(r[i-1,j],r[i,j-1]),\quad x[i]!=y[j] \end{cases} r[i,j]=⎩⎪⎨⎪⎧r[i−1,j−1]+1,x[i]=y[j]max(r[i−1,j],r[i,j−1]),x[i]!=y[j] - 复杂度: O ( m n ) \Omicron(mn) O(mn)
-
其它最长公共子序列问题:
-
允许X中元素重复出现:
r [ i , j ] = { r [ i , j − 1 ] + 1 , x [ i ] = y [ j ] m a x ( r [ i − 1 , j ] , r [ i , j − 1 ] ) , x [ i ] ! = y [ j ] r[i,j]=\begin{cases} r[i,j-1]+1,\quad\quad\quad\quad\quad x[i]=y[j] \\\\ max(r[i-1,j],r[i,j-1]),\quad x[i]!=y[j] \end{cases} r[i,j]=⎩⎪⎨⎪⎧r[i,j−1]+1,x[i]=y[j]max(r[i−1,j],r[i,j−1]),x[i]!=y[j] -
前向后向连续公共子序列
- 输入: x [ 1... n ] x[1...n] x[1...n]
- 定义子问题:
r
[
i
,
j
]
r[i,j]
r[i,j]表示以x[i]开始,以x[j]结尾的最长连续子序列,只要带上
连续
就是这个板子 - 目标:求所有 r [ i , j ] r[i,j] r[i,j]的最大值
- 初始化: r [ i , i + 1 ] = I { x [ i ] = = x [ i + 1 ] } , r [ i , i ] = 0 r[i,i+1]=I\left\{x[i]==x[i+1]\right\},r[i,i]=0 r[i,i+1]=I{x[i]==x[i+1]},r[i,i]=0
- 递归式:
r [ i , j ] = { r [ i + 1 , j − 1 ] + 1 , x [ i ] = x [ j ] 0 , x [ i ] ! = x [ j ] r[i,j]=\begin{cases} r[i+1,j-1] + 1,\quad x[i]=x[j] \\\\ 0,\quad x[i]!=x[j] \end{cases} r[i,j]=⎩⎪⎨⎪⎧r[i+1,j−1]+1,x[i]=x[j]0,x[i]!=x[j]
-
-
最大连续和字串的DP解
- 输入:x[1…n]
- 定义子问题:r[i]是以x[i]为结尾的最大连续和字串
- 目标:求r[1…n]的最大值
- 初始化:r[0…n]=0;
- 递归式:
r [ i ] = { r [ i − 1 ] + x [ i ] , r [ i − 1 ] > 0 x [ i ] , r [ i − 1 ] ≤ 0 r[i]=\begin{cases} r[i-1]+x[i],\quad r[i-1] > 0 \\\\ x[i],\quad\quad\quad\quad\quad r[i-1]\leq0 \end{cases} r[i]=⎩⎪⎨⎪⎧r[i−1]+x[i],r[i−1]>0x[i],r[i−1]≤0 - 伪代码:
for i:=0 to n r[i] = 0 for i:=1 to n r[i]=max(x[i],x[i]+r[i-1])
- 复杂度:O(n)
-
word to line问题
- 一维的啊…写累了,这个有点难,懒得写了。
-
其他问题:
- 回文字串问题:注意长度的定义方式,递归式里是+2还是+1。
- 回文串
分割
问题:(就感觉带分割
的问题都是在找k个分割点),有 O ( n 2 ) O(n^2) O(n2)解