题目描述
给定两个长度分别为n和m的序列A和B,求两个序列的最长公共上升子序列长度。
例如:
1 5 3 6 3 2 7 3 6 2 和 9 6 2 3 1 5 3 3 6 1 的最长上升子序列的长度为3。
题目分析
这是一道LIS和LCS的综合题目。
【状态定义】:dp[i][j]dp[i][j]dp[i][j]表示序列A[1:i]A[1:i]A[1:i]和序列B[1:j]B[1:j]B[1:j]构成的以B[j][B[j][B[j][为结尾的LCIS长度。
【状态转移】 为:
- A[i]≠B[j]A[i] ≠ B[j]A[i]=B[j] :dp[i][j]=dp[i−1][j]dp[i][j] = dp[i-1][j]dp[i][j]=dp[i−1][j] (可以理解为将A[i]A[i]A[i]扔掉)
- A[i]=B[j]A[i] = B[j]A[i]=B[j] :dp[i][j]=max{dp[i−1][k]}dp[i][j] = max\{ dp[i-1][k]\}dp[i][j]=max{dp[i−1][k]} , kkk 满足: k∈[0,j),B[k]<B[j]k∈[0,j) ,B[k]<B[j]k∈[0,j),B[k]<B[j]
dp[][j]dp[][j]dp[][j]的子问题不是dp[][j−1]dp[][j-1]dp[][j−1],而是满足单调性的dp[][k]dp[][k]dp[][k]
【边界条件】:dp[0][j]=dp[i][0]=0dp[0][j] = dp[i][0] = 0dp[0][j]=dp[i][0]=0
【目标状态】:max{dp[n][j]}max\{dp[n][j]\}max{dp[n][j]}, j∈[1,m]j ∈[1,m]j∈[1,m]
代码
int cal(){
a[0] = b[0] = -inf;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i] != b[j]) dp[i][j] = dp[i-1][j];
else{
for(int k = 0;k<j;k++){ //注意k=0开始
if(b[k]<b[j])
dp[i][j] = max(dp[i][j],dp[i-1][k]+1);
}
}
}
}
int ans=-inf;
for(int j=1;j<=m;j++) ans = max(ans,dp[n][j]);
return ans;
}
【细节注意】
当BBB串当中,找不到B[k]B[k]B[k]满足B[k]<B[j]B[k]<B[j]B[k]<B[j]时,B[0]B[0]B[0]充当满足条件的B[k]B[k]B[k],那么对于BBB串来说,以B[j]B[j]B[j]为结尾的LIS长度为1,即B[j]B[j]B[j]本身。因此:
- A[0]A[0]A[0]和B[0]B[0]B[0] 定义为-∞。
- kkk从000开始枚举
优化
注意观察状态转移公式,当A[i]=B[j]A[i] = B[j]A[i]=B[j]时,决策集合为$ dp[i-1][k],,,k 满足满足满足k∈[0,j) ,B[k]<B[j]$ ,由于A[i]=B[j]A[i] = B[j]A[i]=B[j],即为满足k∈[0,j),B[k]<A[i]k∈[0,j) ,B[k]<A[i]k∈[0,j),B[k]<A[i]。 在内层循环中,iii 的值不变,jjj的值递增。即决策集合的改变只受B[j]B[j]B[j]的影响,如果B[j]<A[i]B[j]<A[i]B[j]<A[i],则dp[i−1][j]dp[i-1][j]dp[i−1][j]进入决策集合,否则决策集合不变。
定义变量vvv为每轮最初的决策集合结果值,jjj递增前,判断:
- B[j]<A[i]B[j]<A[i]B[j]<A[i], v=max(v,dp[i−1][j])v = max(v, dp[i-1][j])v=max(v,dp[i−1][j])
- B[j]≥A[i]B[j] ≥ A[i]B[j]≥A[i], vvv不变
代码
int cal(){
a[0] = b[0] = -inf;
for(int i=1;i<=n;i++){
int v=0;
for(int j=1;j<=m;j++){
if(a[i] != b[j]) dp[i][j] = dp[i-1][j];
else dp[i][j] = v+1;
if(b[j] < a[i]) v = max(v,dp[i-1][j]);
}
}
int ans=-inf;
for(int j=1;j<=m;j++) ans = max(ans,dp[n][j]);
return ans;
}
本文解析了如何解决两个序列的最长公共上升子序列问题,通过状态转移优化了动态规划算法,介绍了状态定义、转移方程、边界条件和代码实现。关键在于理解单调性并利用决策集合的简化。
&spm=1001.2101.3001.5002&articleId=119918103&d=1&t=3&u=f6e7dbde41484d3aae80e2c3e02aa896)
3670

被折叠的 条评论
为什么被折叠?



