zoukankan      html  css  js  c++  java
  • [DP] LCS小结

    额、、失误、、

    LCS是Longest Common Subsequence的缩写,即最长公共子序列。一个序列,如果是两个或多个已知序列的子序列,且是所有子序列中最长的,则为最长公共子序列。

    DP、O(n^2)解法:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define max(a,b) ((a)>(b)?(a):(b))
    #define N 1010
    
    int p,q;
    int a[N];
    int b[N];
    int dp[N][N];
    
    void solve()
    {
        int i,j;
        memset(dp,0,sizeof(dp));
        for(i=1;i<=p;i++)
        {
            for(j=1;j<=q;j++)
            {
                if(a[i]==b[j])
                {
                    dp[i][j]=dp[i-1][j-1]+1;
                }
                else
                {
                    dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        cout<<dp[p][q]<<endl;
    }
    int main()
    {
        int i;
        while(scanf("%d%d",&p,&q)!=EOF)
        {
            for(i=1;i<=p;i++)
            {
                scanf("%d",&a[i]);
            }
            for(i=1;i<=q;i++)
            {
                scanf("%d",&b[i]);
            }
            solve();
        }
        return 0;
    }

    O(nlogn)解法:

    参考http://www.cs.ucf.edu/courses/cap5937/fall2004/Longest%20common%20subsequence.pdf

    最长公共子序列 的 nlogn 的算法本质是 将该问题转化成 最长增序列(LIS),因为 LIS 可以用nlogn实现,所以求LCS的时间复杂度降低为 nlogn。

    转化:将LCS问题转化成LIS问题。

                   假设有两个序列 s1[ 1~6 ] = { a, b, c , a, d, c }, s2[ 1~7 ] = { c, a, b, e, d, a, b }。

                   记录s1中每个元素在s2中出现的位置, 再将位置按降序排列, 则上面的例子可表示为:

                   loc( a)= { 6, 2 }, loc( b ) = { 7, 3 }, loc( c ) = { 1 }, loc( d ) = { 5 }。

                   将s1中每个元素的位置按s1中元素的顺序排列成一个序列s3 = { 6, 2, 7, 3, 1, 6, 2, 5, 1 }。

                   在对s3求LIS得到的值即为求LCS的答案。(这点我也只是大致理解,读者可以自己理解甚至证明。)

    上面一段话转载自:http://blog.csdn.net/non_cease/article/details/6918848

    1、当无重复元素时:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define N 1010
    
    int len;
    int p,q;
    int a[N];
    int b[N];
    int dp[N];
    
    void convert()
    {
        int i,hash[N]={0};
        for(i=1;i<=p;i++)
        {
            hash[a[i]]=i;
        }
        for(i=1;i<=q;i++)
        {
            b[i]=hash[b[i]];
        }
    }
    int up_bound(int k)
    {
        int l=1,r=len+1;
        while(l<r)
        {
            int m=(l+r)>>1;
            if(dp[m]<=k) l=m+1;
            else r=m;
        }
        return l;
    }
    void solve()
    {
        len=0;
        dp[0]=-0x7ffffff;
        for(int i=1;i<=q;i++)
        {
            if(!b[i]) continue;
            if(b[i]>dp[len]) dp[++len]=b[i];
            else
            {
                int pos=up_bound(b[i]);
                dp[pos]=b[i];
            }
        }
        printf("%d
    ",len);
    }
    int main()
    {
        while(scanf("%d%d",&p,&q)!=EOF)
        {
            for(int i=1;i<=p;i++)
            {
                scanf("%d",&a[i]);
            }
            for(int i=1;i<=q;i++)
            {
                scanf("%d",&b[i]);
            }
            convert();
            solve();
        }
        return 0;
    }

    2、当有重复元素时:

    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    using namespace std;
    #define N 10010
    
    int n;
    int p,q;
    int len;
    int a[N];
    int b[N];
    int s[N];
    int dp[N];
    
    void convert()
    {
        vector<int> v[N];
        for(int i=1;i<=p;i++)
        {
            v[a[i]].push_back(i);
        }
        n=0;
        for(int i=1;i<=q;i++)
        {
            for(int j=v[b[i]].size()-1;j>=0;j--)
            {
                s[++n]=v[b[i]][j];
            }
        }
    }
    int up_bound(int k)
    {
        int l=1,r=len+1;
        while(l<r)
        {
            int m=(l+r)>>1;
            if(dp[m]<=k) l=m+1;
            else r=m;
        }
        return l;
    }
    
    void solve()
    {
        len=0;
        dp[0]=-0x7fffffff;
        for(int i=1;i<=n;i++)
        {
            if(s[i]>dp[len]) dp[++len]=s[i];
            else
            {
                int pos=up_bound(s[i]-1);
                dp[pos]=s[i];
            }
        }
        printf("%d
    ",len);
    }
    int main()
    {
        while(scanf("%d%d",&p,&q)!=EOF)
        {
            for(int i=1;i<=p;i++)
            {
                scanf("%d",&a[i]);
            }
            for(int i=1;i<=q;i++)
            {
                scanf("%d",&b[i]);
            }
            convert();
            solve();
        }
        return 0;
    }
    趁着还有梦想、将AC进行到底~~~by 452181625
  • 相关阅读:
    maven 错误:读取 xxx.jar 时出错;invalid LOC header (bad signature) 1 错误
    设计模式总结篇系列:建造者模式(Builder)
    java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to
    Rxlifecycle使用详解,解决RxJava内存泄露问题
    详细解析RxAndroid的使用方式
    Android开源项目:GifView——Android显示GIF动画
    Rxjava2的学习与总结
    Pycharm连接gitlab
    Pycharm+Django+Python+MySQL开发 后台管理数据库
    Django-Model操作数据库(增删改查、连表结构)
  • 原文地址:https://www.cnblogs.com/hate13/p/4150815.html
Copyright © 2011-2022 走看看