LCIS

求最长公共上升子序列
例题:UVA12511
算法:
dp[i][j]表示a[1] ~ a[i]和b[1] ~ b[j]并以b[j]结尾的最长公共上升子序列,如果a[i]不等于b[j]时,很明显dp[i][j]的值就等于dp[i-1][j];如果a[i]等于b[j]时,就在b[1]~b[j]中寻找b[k]使得b[j]>b[k]而且dp[i][k]是最大的。即状态转移方程为:dp[i][j] = dp[i-1][j](a[i] != b[j]),dp[i][j] = max(dp[i][k])+1(1<=k<j && b[j]>b[k]).
当a[i] == b[j]时,才去遍历寻找max1,是在b[j]>b[k]的条件下,即在a[i]>b[k]所以可以先在[1,m]里面保存好max1的值,然后当a[i] == b[j]时,就可以直接令dp[i][j]=max1+1,时间复杂度就降为O(n^2);

#include<bits/stdc++.h>
using namespace std;
int a[1111],b[1111];    //存A,B串
int dp[1111][1111];     //dp[i][j]表示a[1]~a[i]和b[1]~b[j]并以b[j]结尾的LCIS
int main(){             //本例DP的理解关键是必须以BJ结尾
    int t,n,m;scanf("%d",&t);   //输出样例数
    while(t--){                 //样例自减
        scanf("%d",&n);         //A串长为N
        for(int i=1;i<=n; i++){ //遍历
            scanf("%d",&a[i]);  //读入N个数
            dp[i][0] = 0;       //因为下标是从1开始的,所以以B[0]结束的LCIS肯定是0
        }
        scanf("%d",&m);         //B串长是M
        for(int i=1;i<=m;i++){  //遍历
            scanf("%d",&b[i]);  //读出M个数
            dp[0][i]=0;         //因为下标是从1开始的,所以与A[0]匹配的LCIS肯定是0
        }
        dp[0][0]=0;             //定义DP00就是0,没啥好说的,至此初始化及输入完成
        int max1;               //然后生成DP矩阵
        for(int i=1;i<=n;i++){  //大循环A串下标遍历
            max1=0;//用于a[i]==b[j]时.寻找前面比b[j](即a[i])小且最大的dp[i][k](1=<k<j)
            for(int j=1;j<=m;j++){//二循环B串下标遍历
                if(a[i]== b[j])dp[i][j]=max1+1;//匹配成功,当前DP就是最大值加1,这个MAX1保证了前已排好的升序且是最大长度
                else dp[i][j]=dp[i-1][j];//不匹配,则当前DP就是与A串的[0~i-1]的LCIS,因为A串的I位对当前DP无贡献,B串还是以BJ结尾,这个是不变的
                if(a[i]>b[j]&&max1<dp[i][j])max1=dp[i][j];//看当前DPIJ能否更新MAX1
            }//MAX1是本轮不断往后更新用的,记录比a[i]小且最大的dp[i][k](1=<k<j),至关键就是句维护了,不然要扫一次
        }//a[i]>b[j]是因为现在要求升序,当前BJ还比AI小,讲明更大的能与AI匹配的BJ(如果有)在后面
        int ans = 0;                //开始求解,初始化答案是0
        for(int i = 1;i<=m;i++)     //遍历B串的下标
            ans = max(ans,dp[n][i]);//以B[0]为左界,B串每个下标为右界(必须以其结尾)与A整个串匹配的最大长度就是答案
        printf("%d\n",ans);         //输出答案
    }
    return 0;
}
/*
Sample Input 
1
9 1 4 2 6 3 8 5 9 1 
6 2 7 6 3 5 1 
Sample Output 
3
*/

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值