最长公共子序列的另一类优化方法

来源:互联网 发布:ubuntu怎么添加输入法 编辑:程序博客网 时间:2024/05/22 03:21

    最长公共子序列(LCS)是一个很经典的问题。  给2个字符串s1,s2,求LCS(s1,s2). 用d[i][j]]表示s1[1-i]和是s2[1-j]的LCS. 

if(s1[i]==s2[j]) d[i][j]=d[i-1][j-1]+1 

else  d[i][j]=max(d[i-1][j],d[I][j-1]).

这是一个1D/1D的动态规划问题,复查度为O(n*n)。 考虑如下特殊的LCS问题.求2个全排列p1,p2的LCS。

这个问题的特殊性在于,每个数只出现一次。我们观察转移方程,只有在是p1[i]==p2[j] 的时候才会出现+1的转移。那么其实有

我们用pari[i]表示s1[i]在s2[i]中出现的位置。 可以得出d[i][pari[i]]=max{d[l'][j']}+1 .i>l;.pari[i]>j'。这样可以用一个数据结构在维护,复杂度可以降低到nlogn级别



例1:

uva10635 

#include <set>#include <map>#include <queue>#include <stack>#include <cmath>#include <string>#include <cctype>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int inf  = 0x3fffffff;const int mmax = 250*250+10;map<int,int>q;int p1[mmax],p2[mmax];int pos[mmax];int C[mmax];int n;int low_bit(int x){    return x&(-x);}void update(int pos,int val){    for(int i=pos;i<=n;i+=low_bit(i))        C[i]=max(C[i],val);}int get_max(int x){    int ans=0;    for(int i=x;i>0;i-=low_bit(i))        ans=max(ans,C[i]);    return ans;}int main(){    int t,ca=0;    cin>>t;    while(t--)    {        int d,l1,l2;        q.clear();        scanf("%d %d %d",&d,&l1,&l2);        l1++,l2++;        for(int i=1;i<=l1;i++)            scanf("%d",&p1[i]);        for(int i=1;i<=l2;i++)        {            scanf("%d",&p2[i]);            q[p2[i]]=i;        }        memset(C,0,sizeof C);        n=l2;        int ans=0;        for(int i=1;i<=l1;i++)        {            if(!q.count(p1[i]))                continue;            int y=q[p1[i]];            int tmp=get_max(y)+1;            ans=max(ans,tmp);            update(y,tmp);        }        printf("Case %d: %d\n",++ca,ans);    }    return 0;}

这题还有一种特别的解法,用映射的手段,吧s1的映射成,1,2,3,4.。。。n,求s2 的最长上升序列。用n*logn的算法

#include <set>#include <map>#include <queue>#include <stack>#include <cmath>#include <string>#include <cctype>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int inf  = 0x3fffffff;const int mmax = 250*250+10;int p1[mmax],p2[mmax];int dp[mmax];map<int,int>q;int main(){    int t,ca=0;    cin>>t;    while(t--)    {        int d,l1,l2;        q.clear();        scanf("%d %d %d",&d,&l1,&l2);        l1++,l2++;        for(int i=1;i<=l1;i++)        {            scanf("%d",&p1[i]);            q[p1[i]]=i;        }        for(int i=1;i<=l2;i++)        {            int x;            scanf("%d",&x);            if(!q.count(x))                p2[i]=0;            else                p2[i]=q[x];        }        int len=1;        dp[1]=p2[1];        for(int i=2;i<=l2;i++)        {            int l=1,r=len+1;            int mid=(l+1)>>1;            while(l<r)            {                mid=(l+r)>>1;                if(dp[mid]<p2[i])                    l=mid+1;                else                    r=mid;            }            dp[r]=p2[i];            if(r==len+1)                len++;        }        printf("Case %d: %d\n",++ca,len);    }    return 0;}


例题2 

解法自行YY,给出AC代码

#include <set>#include <map>#include <queue>#include <stack>#include <cmath>#include <string>#include <cctype>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <algorithm>using namespace std;typedef long long LL;const int inf  = 0x3fffffff;const int mmax =100010;map<int,int>q;int p1[mmax],p2[mmax];int next[mmax];int C[mmax];int n;int low_bit(int x){    return x&(-x);}void update(int pos,int val){    for(int i=pos;i<=n;i+=low_bit(i))        C[i]=max(C[i],val);}int get_max(int x){    int ans=0;    for(int i=x;i>0;i-=low_bit(i))        ans=max(ans,C[i]);    return ans;}int main(){    while(cin>>n)    {        n*=5;        q.clear();        for(int i=1;i<=n;i++)            scanf("%d",&p1[i]);        memset(next,-1,sizeof next);        for(int i=1;i<=n;i++)        {            scanf("%d",&p2[i]);            if(!q.count(p2[i]))                q[p2[i]]=i;            else            {                next[i]=q[p2[i]];                q[p2[i]]=i;            }        }        memset(C,0,sizeof C);        int ans=0;        for(int i=1;i<=n;i++)        {            if(!q.count(p1[i]))                continue;            int y=q[p1[i]];            while(y+1)            {                int tmp=get_max(y-1)+1;                ans=max(ans,tmp);                update(y,tmp);                y=next[y];            }        }        printf("%d\n",ans);    }    return 0;}



0 0