经典动态规划模型归纳总结(最大连续子序列和、LIS、LCS、最长回文子串、数塔DP、DAG最长路、01背包、完全背包)

1 模型列举

1.1最大连续子序列和

详细内容
令dp[i]表示A[i]结尾的连续序列最大和(A[i]必须为连续序列的末尾)【不然就会产生多个相同的dp[i]】。

状态转移方程:
d p [ i ] = m a x ( A [ i ] , d [ i − 1 ] + A [ i ] ) ; dp[i] = max (A[i], d[i -1] + A[i]); dp[i]=max(A[i],d[i1]+A[i]);
边界:
d p [ 0 ] = 0 ; dp[0] = 0; dp[0]=0;

1.2最长不下降子序列(LIS)

详细内容
令dp[i]表示最长不下降序列长度(必须以A[i]结尾)。

状态转移方程
d p [ i ] = m a x j ∈ 1 , 2 , . . . , i − 1 并 且 A [ j ] < A [ i ] ( 1 , d p [ j ] + 1 ) dp[i] = max_{ j \in 1,2,...,i -1 并且 A[j] < A[i]} {(1, dp[j] + 1)} dp[i]=maxj1,2,...,i1A[j]<A[i](1,dp[j]+1)

边界:
d p [ i ] = 1 dp[i] = 1 dp[i]=1

1.3 最长公共子序列LCS

详细内容
令dp[i][j]表示字符串A的i号位和字符串B的j号位之前的LCS长度(下标从1开始)。

状态转移方程
d p [ i ] [ j ] = { d p [ i − 1 ] [ j − 1 ] , A [ i ] = B [ i ] m a x { d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] } , A [ i ] ! = B [ i ] dp[i][j]=\left\{ \begin{aligned} dp[i-1][j-1],A[i] = B[i] \\ max\{dp[i-1][j],dp[i][j-1]\},A[i] != B[i] \\ \end{aligned} \right. dp[i][j]={dp[i1][j1],A[i]=B[i]max{dp[i1][j],dp[i][j1]},A[i]!=B[i]
边界:
d p [ i ] [ 0 ] = d p [ 0 ] [ j ] = 0 ( 0 < = i < = n , 0 < = j < = m ) dp[i][0] = dp[0][j] = 0(0<= i <= n, 0 <= j <=m) dp[i][0]=dp[0][j]=0(0<=i<=n,0<=j<=m)

1.4 最长回文子串

详细内容
令dp[i][j]表示S[i]至S[j]所表示的子串是否是回文串,是则为1,不是为0。

状态转移方程
d p [ i ] [ j ] = { d p [ i + 1 ] [ j − 1 ] , S [ i ] = S [ i ] 0 , S [ i ] ! = S [ i ] dp[i][j]=\left\{ \begin{aligned} dp[i+1][j-1],S[i] = S[i] \\ 0,S[i] != S[i] \\ \end{aligned} \right. dp[i][j]={dp[i+1][j1],S[i]=S[i]0,S[i]!=S[i]

边界:
d p [ i ] [ i ] = 0 , d p [ i ] [ i + 1 ] = ( S [ i ] = = S [ i + 1 ] ) ? 1 : 0 dp[i][i] = 0, dp[i][i+1] = (S[i] == S[i+1])? 1 : 0 dp[i][i]=0,dp[i][i+1]=(S[i]==S[i+1])?1:0

1.5 数塔DP

详细内容
令dp[i][j]表示从第i行第j个数字出发的到达最低层的所有路径上所能得到的最大和。

状态转移方程
d p [ i ] [ j ] = m a x ( d p [ i + 1 ] [ j ] , d p [ i + 1 ] [ j + 1 ] ) + f [ i ] [ j ] dp[i][j] = max(dp[i+1][j], dp[i + 1][j +1])+f[i][j] dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+f[i][j]
边界(直接确定其结果):数组dp最后一层dp总是等于元素自身

1.6 DAG最长路

详细内容
令dp[i]表示从i号顶点出发的获得的最长路径长度。

状态转移方程
不固定终点/不固定终点:
d p [ i ] = m a x { d p [ j ] + l e n g h t [ i ⟶ j ] | ( i , j ∈ E ) } dp[i] = max\{dp[j] + lenght[i \longrightarrow j] |(i,j\in E)\} dp[i]=max{dp[j]+lenght[ij](i,jE)}
边界:
不固定终点:
从出度为0的顶点出发的最长路径长度为0(对整个数组dp初始化为0)
固定终点:
d p [ T ] = 0 dp[T] = 0 dp[T]=0(T为终点,初始化dp数组作为一个负的大数)

1.8 0-1背包

详细内容
令dp[i][v]表示前i件物品( 1 ≤ \leq i ≤ \leq n, 0 ≤ \leq v ≤ \leq V)恰好装入容量为v的背包中所能获得的最大值。

状态转移方程
d p [ i ] [ v ] = m a x 1 ≤ i ≤ n , w [ i ] ≤ v ≤ V { d p [ i − 1 ] [ v ] , d p [ i − 1 ] [ v − w [ i ] ] + c [ i ] } dp[i][v] = max_{ 1 \leq i \leq n,w[i] \leq v \leq V }{\{dp[i-1][v], dp[i-1][v - w[i]]+ c[i]\}} dp[i][v]=max1inw[i]vV{dp[i1][v],dp[i1][vw[i]]+c[i]}

边界:
d p [ 0 ] [ v ] = 0 ( 0 ≤ v ≤ V ) dp[0][v]=0(0 \leq v \leq V) dp[0][v]=00vV)

1.9 完全背包

详细内容
令dp[i][v]表示前i件物品( 1 ≤ \leq i ≤ \leq n, 0 ≤ \leq v ≤ \leq V)恰好装入容量为v的背包中所能获得的最大值。

状态转移方程:
d p [ i ] [ v ] = m a x 1 ≤ i ≤ n , w [ i ] ≤ v ≤ V { d p [ i − 1 ] [ v ] , d p [ i ] [ v − w [ i ] ] + c [ i ] } dp[i][v] = max_{ 1 \leq i \leq n,w[i] \leq v \leq V }{\{dp[i-1][v], dp[i][v - w[i]]+ c[i]\}} dp[i][v]=max1inw[i]vV{dp[i1][v],dp[i][vw[i]]+c[i]}
边界:
d [ 0 ] [ v ] = 0 ( 0 ≤ v ≤ V ) d[0][v] = 0 (0 \leq v \leq V) d[0][v]=0(0vV)

2 总结

2.1 类型一

XXX:为原问题的描述

  • 第一节1~4都是有关序列或字符串的问题(一般来说“子序列可以不连续、子串必须要连续”),
    • (1)(2)的设计状态都是“令dp[i]表示以A[i]结尾的XXX”,
    • 而 (3)(4)由于原问题本身就有二维性质,因此使用了“令dp[i][j]表示i号位和j号位之间XXX“的状态设计方式“

当题目与序列和字符串(记为A)有关时,可以考虑把状态设计为下面两种形式,然后根据端点特性考虑状态转移方程。

  • 1 令dp[i]表示以A[i]结尾(或开头)的XXX;
  • 2 令dp[i][j]表示i号位和j号位之间XXX。

2.2 类型二

(5)~(8),它们的状态设计都包括了某种“方向” 的意思,
如数塔DP设计为从(i,j)出发到达最底层的最大和
DAG设计为从i号顶点出发的最长路
背包问题设计为前i件物品恰好放容量为v的背包中能获得的最大价值。

当题目中的状态需要几维来表示,然后对其中的每一维采取下面的某一种描述:

  • 1 恰好为i;
  • 2 前i;
    在每一维的含义设计完毕之后,dp数组的含义就可以设置为“令dp数组恰好为i(或前i),恰好为j(或前j)……的XXX”,然后就可以通过端点的特性来考虑状态转移方程。

大多数情况,可以把动态规划可解的问题看成一个有向无环图(DAG),图中的结点就是状态,边就是状态转移方向,求解问题的顺序就可以按照DAG的拓扑顺序进行求解。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星蓝雨

如果觉得文章不错可以请喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值