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
  • 相关阅读:
    如何查看哪些软件或进程占用了网速
    关于str.split(",")中间 什么时候该加\转义
    【转】servlet/filter/listener/interceptor区别与联系
    专题-Delphi/C++ Builder多线程编程与调试
    Android点击图标重新启动问题
    用PHP判断远程图片(文件)是否存在
    php获取目录中的所有文件名
    PHP读取一个目录下的文件个数
    2>&1 的用法说明
    【PHP操作sphinx】
  • 原文地址:https://www.cnblogs.com/ACRykl/p/8296152.html
Copyright © 2011-2022 走看看