LCIS(最长公共上升子序列)

本文解析了如何解决两个序列的最长公共上升子序列问题,通过状态转移优化了动态规划算法,介绍了状态定义、转移方程、边界条件和代码实现。关键在于理解单调性并利用决策集合的简化。
题目描述

给定两个长度分别为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。

题目分析

这是一道LISLCS的综合题目。

【状态定义】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[i1][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[i1][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[][j1],而是满足单调性的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] 定义为-∞。
  • kkk000开始枚举
优化

注意观察状态转移公式,当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[i1][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[i1][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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值