动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使问题能通过递推或者分治的方式去解决
动态规划问题,要明确状态和转移两个问题
例题1:
数字三角形问题:
规则:往下走(正下、右斜下),求和最大
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
7+3+8+7+5=30
状态:定义状态f[i][j]表示从(1,1)除非走到(i,j)所有路径的最大和,例如f[3][2]={7+3+1,7+8+1}=16,而答案来自f[n][1...n]中的最大值
转移:考虑哪些状态对f[i][j]这个状态有影响
只有两种情况:(i-1,j)->(i,j)和(i-1,j-1)->(i,j),那么f[i][j]=max(f[i-1][j],f[i-1][j-1])+a[i][j]
状态要明确两点:
- 初始状态:f[1][1]=a[1][1],但是对于f[n][1]总是回去上一行左侧不存在的数f[n-1][0],对于f[n][n]也不存在正上方的数,可以定义为-∞或者0或者∞,具体看题目需求来决定。
- 答案在哪?答案来自f[n][1...n]中的最大值,即最后一排中的最大值
注意转移顺序,只有上一次都转移了,下一层才能用上一层数据
例题2:
最长上升子序列(LIS):
数据:1 13 5 7 8 2 11
转移:1 2 2 3 4 2 5
前置:0 1 1 3 4 1 5
答案:1 5 7 8 11
子序列不一定是连续的~
状态:f[i]表示以i结尾的上升子序列中的最长长度
转移:当j<i,且a[j]<a[i]时,f[i]=max{f[j]+1} (j:0->i-1),例如当a[i]=8时,取1(f[1])、5(f[3])、7(f[4])的中最大的f值+1即为f[5],而13是不会取的
初始状态:均为1,答案选取:max(f[1]...f[n]),同时可以设置一个前置数组(pre)记录从哪里转移过来的
其他经典问题:最长公共子序列、最大字段和、最长公共上升子序列、背包问题(九种)
例题3:
最长公共子序列:
状态:f[i][j]表示两个字符串X的前i个,Y字符串前j个字符的LCS的长度
转移:如果i,j>0且X[i]==Y[j],f[i,j]=f[i-1,j-1]+1;如果如果i,j>0且X[i]!=Y[j],f[i,j]=max{f[i-1][j],f[i][j-1]}
初试状态:f[i][0]=f[0][j]=0
初始化:
B D C A
0 0 0 0 0
A 0
B 0
C 0
B 0
首先看f[1][1]:AB不相等:取max{f[1][0],f[0][1]}(以后本部分直接用数字代替)=0
f[1][2]=AD->max{0,0}=0
f[1][3]=AC->max{0,0}=0
f[1][4]=AA->f[0][3]+1=1
第一行更新后:
B D C A
0 0 0 0 0
A 0 0 0 0 1
B 0
C 0
B 0
同理:f[2][1]=BB->f[1][0]+1=1
f[2][2]=BD->max{0,1}=1
f[2][3]=BC->max{0,1}=1
f[2][4]=BA->max{0,1}=1
第二行更新后:
B D C A
0 0 0 0 0
A 0 0 0 0 1
B 0 1 1 1 1
C 0
B 0
以下同理:
最后的矩阵:
B D C A
0 0 0 0 0
A 0 0 0 0 1
B 0 1 1 1 1
C 0 1 1 2 2
B 0 1 1 2 2
例题4:
背包问题(0-1):
状态:f[i][j]表示前i个物品,占体积j,能得到的最大价值
转移:f[i][j]=max{f[i-1][j],f[i-1][j-v[i]]+w[i]},考虑第i个物品取还是不取,取则从f[i-1][j-v[i]]+w[i]转移过来,不取则从f[i-1][j]转移过来
number=4,capacity=8
I: 1 2 3 4
体积:2 3 4 5
价值:3 4 5 6
初始化边界条件,V(0,j)=V(i,0)=0
i/j 0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0
2 0
3 0
4 0
i=1,j=1,w(1)=2,v(1)=3,有j<w(1),故V(1,1)=V(1-1,1)=0;
i=1,j=2,w(1)=2,v(1)=3,有j=w(1),故V(1,2)=max{ V(1-1,2),V(1-1,2-w(1))+v(1) }=max{0,0+3}=3;
i=4,j=8,w(4)=5,v(4)=6,有j>w(4),故V(4,8)=max{ V(4-1,8),V(4-1,8-w(4))+v(4) }=max{9,4+6}=10
最终如下:
初始化边界条件,V(0,j)=V(i,0)=0
i/j 0 1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0 0 0
1 0 3 3 3 3 3 3 3 3
2 0 3 3 4 4 7 7 7 7
3 0 3 3 4 5 7 8 9 9
4 0 3 3 4 5 7 8 9 10
大概这四个例题就足够能理解动态规划了
以上学习内容来自北京理工大学ACM冬季培训课程(b站公开课)学习加自己整理的部分内容,链接:https://www.bilibili.com/video/av92947660?t=3520&p=6