zoukankan      html  css  js  c++  java
  • uva10635(最长上升子列)

    题意:给出两个数列,每个数列的数都不同,求两个数列的最长公共子列(LCS),输出长度。

    分析:LCS转化为LIS。因为两个数组中每个数都不同,所以先将A数组按顺序对应1,2,3,4...p+1,

    再把B数组与A数组共有的数用1,2,3...p+1替换,仅B数组中有的数则舍去,形成一个新序列 C ,

    再求C的最长上升序列(LIS)。

    复杂度n*n代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>//最长上升子列 
    using namespace std;
    int A[1000000],B[1000000],dp[1000000];
    int main()
    {
        int T,cas=0,n,N,M;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d%d",&n,&N,&M);
            memset(A,0,sizeof(A));
            int x;
            for(int i=1;i<=N+1;i++)
            {
                scanf("%d",&x);
                A[x]=i;
            }
            int len=0;
            for(int i=1;i<=M+1;i++)
            {
                scanf("%d",&x);
                if(A[x]) B[len++]=A[x];
            }
            //求数组B的LIS,最长上升子列 
    /*考虑B[i]的决策,B[i]要么为前i个数中某个LIS的结尾,要么是开头第一个数 
    dp[i]为以B[i]为结尾的LIS 
    j:0->i-1 if(B[i]>B[j]) dp[i]=dp[j]+1;else dp[i]=1;
    */        
            memset(dp,0,sizeof(dp));
            dp[0]=1;
            int ans=0;
            /*for(int i=1;i<len;i++)超时 
            {
                for(int j=0;j<i;j++)
                if(B[i]>B[j]&&dp[j]>dp[i]) dp[i]=dp[j];
                dp[i]++;
                ans=max(ans,dp[i]);
            }*/
            for(int i=1;i<len;i++) 
            {
                dp[i]=1;
                for(int j=0;j<i;j++)
                if(B[i]>B[j]) dp[i]=max(dp[j]+1,dp[i]);
                ans=max(ans,dp[i]);
            }
            printf("Case %d: %d
    ",++cas,ans);
        }
        return 0;
    }
    View Code

    复杂度nlogn

    #include<cstdio>
    #include<cstring>
    #include<algorithm>//最长上升子列 
    #define INF 999999999
    using namespace std;
    int A[90000],B[90000],dp[90000];
    int main()
    {
        int T,cas=0,n,N,M;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d%d",&n,&N,&M);
            memset(A,0,sizeof(A));
            int x;
            for(int i=1;i<=N+1;i++)
            {
                scanf("%d",&x);
                A[x]=i;
            }
            int len=0;
            for(int i=1;i<=M+1;i++)
            {
                scanf("%d",&x);
                if(A[x]) {dp[len]=INF;B[len++]=A[x];}
            }
    /*dp[i]表示长度为i+1的上升子列末尾元素的最小值,则dp[i]必递增,所以可以用二分法,初始化dp[i]=INF*/
            for(int i=0;i<len;i++)
                *lower_bound(dp,dp+len,B[i])=B[i];//找到不大于B[i]的第一个元素,替换成B[i] 
            printf("Case %d: %d
    ",++cas,lower_bound(dp,dp+len,INF)-dp);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    两个数组的交集
    左叶子之和
    下载安装python
    占位
    2020 软件工程实践 助教总结
    安装使用 QEMU-KVM 虚拟化环境(Arch Linux / Manjaro / CentOS / Ubuntu )
    #69. 新年的QAQ
    1097E. Egor and an RPG game(Dilworth定理)
    #553. 【UNR #4】己酸集合
    #2099. 「CQOI2015」标识设计(插头dp)
  • 原文地址:https://www.cnblogs.com/ACRykl/p/8296152.html
Copyright © 2011-2022 走看看