-----[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\n",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\n",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;
}
时间: 2024-11-11 05:04:25

-----[DP] LCS小结的相关文章

LCS小结(O(∩_∩)O~吽吽)

LCS!~如果你在百度上搜这个的话会出来”英雄联盟冠军联赛”,orz..但是今天要讲的LCS是最长公共子序列 ,"Longest Common Subsequence "not"League of Legends Championship Series "小盆友们又要涨姿势了~ 最长公共子序列也称作最长公共子串(不要求连续),打个比方说,A君有一个字符串:qazwbx,B君也有一个字符串:azwsxq,那么我们可以说a君和B君的最长公共子序列为:azwx,长度为4,

poj1458——dp,lcs

poj1458——dp,lcs Common Subsequence Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 40529   Accepted: 16351 Description A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence

hduoj1159 dp,lcs

hduoj1159  dp,lcs Common Subsequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 25570    Accepted Submission(s): 11363 Problem Description A subsequence of a given sequence is the given seq

poj 2250 Compromise dp lcs 路径输出

点击打开链接题目链接 Compromise Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6520   Accepted: 2922   Special Judge Description In a few months the European Currency Union will become a reality. However, to join the club, the Maastricht criteria

UVA-1625-Color Length(DP LCS变形)

Color Length(UVA-1625)(DP LCS变形) 题目大意 输入两个长度分别为n,m(<5000)的颜色序列.要求按顺序合成同一个序列,即每次可以把一个序列开头的颜色放到新序列的尾部. https://odzkskevi.qnssl.com/a68cbd3e27f46b4f02ea12b7b1a1abca 然后产生的新序列中,对于每一个颜色c,都有出现的位置,L(c)表示最小位置和最大位置之差,求L(c)总和最小的新序列. 分析 LCS 是公共上升子序列,在动态转移的过程中,考虑

POJ 1159 Palindrome(DP LCS)

Description A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a program which, given a string, determines the minimal number of characters to be inserted into t

poj1080--Human Gene Functions(dp:LCS变形)

Human Gene Functions Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17206   Accepted: 9568 Description It is well known that a human gene can be considered as a sequence, consisting of four nucleotides, which are simply denoted by four

UVA 11404 Palindromic Subsequence[DP LCS 打印]

UVA - 11404 Palindromic Subsequence 题意:一个字符串,删去0个或多个字符,输出字典序最小且最长的回文字符串 不要求路径区间DP都可以做 然而要字典序最小 倒过来求LCS,转移同时维护f[i][j].s为当前状态字典序最小最优解 f[n][n].s的前半部分一定是回文串的前半部分(想想就行了) 当s的长度为奇时要多输出一个(因为这样长度+1,并且字典序保证最小(如axyzb  bzyxa,就是axb)) // // main.cpp // uva11404 //

LightOJ1033 Generating Palindromes(区间DP/LCS)

题目要计算一个字符串最少添加几个字符使其成为回文串. 一年多前,我LCS这道经典DP例题看得还一知半解时遇到一样的问题,http://acm.fafu.edu.cn/problem.php?id=1007. 当时完全靠自己瞎YY出了LCS的解法: 我当时这么想的: 把字符串分成两个部分,假设这两个部分分别就属于新的回文串的对称的两部分,那么要添加最少的字符串形成回文串就需要前一部分和后一部分公共部分最多,也就是它们的(一正一反)LCS. 这样就是枚举中间部分的位置(另外还要分情况讨论奇数和偶数回