poj 2774 Long Long Message 后缀数组模板

来源:互联网 发布:杭州数据分析企业 编辑:程序博客网 时间:2024/05/18 03:50

先存一下后缀数组DA算法加上求height 数组的模板。

#define N 200012int wa[N],wb[N],wv[N],wws[N];int sa[N],ra[N],height[N];char a[N],b[N];int v[N*3];int cmp(int *r,int a,int b,int l){    return r[a]==r[b]&&r[a+l]==r[b+l];}void da(int n,int m)  //采用基数排序{    int i,j,p,*x=wa,*y=wb;    for(i=0;i<m;i++) wws[i]=0;    for(i=0;i<n;i++) wws[x[i]=v[i]]++;    for(i=1;i<m;i++) wws[i]+=wws[i-1];    for(i=n-1;i>=0;i--) sa[--wws[x[i]]]=i;  // 初始化    for(j=1,p=1;p<n;j*=2,m=p)      {        for(i=n-j,p=0;i<n;i++) y[p++]=i;        for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;   //前两行第二关键字排序        for(i=0;i<n;i++) wv[i]=x[y[i]];        for(i=0;i<m;i++) wws[i]=0;        for(i=0;i<n;i++) wws[wv[i]]++;        for(i=1;i<m;i++) wws[i]+=wws[i-1];            for(i=n-1;i>=0;i--) sa[--wws[wv[i]]]=y[i];     // 到这里五行是第一关键字排序        for(swap(x,y),p=1,i=1,x[sa[0]]=0;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;  //更新排名数组    }    return ;}void getheight(int n){    int i,j,k=0;    for(i=1;i<=n;i++) ra[sa[i]]=i;    for(i=0;i<n;i++)    {        if(k) k--;        j=sa[ra[i]-1];        while(v[i+k]==v[j+k]) k++;        height[ra[i]]=k;    }    return ;}

补全,dc3模板。

注意一下 数组大小要是4*N,N为字符串长度

#define F(x) ((x)/3+((x)%3==1?0:tb))#define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)int c0(int *r,int a,int b){    return r[a]==r[b]&&r[a+1]==r[b+1]&&r[a+2]==r[b+2];}int c12(int k,int *r,int a,int b){    if(k==2) return (r[a]<r[b])||(r[a]==r[b]&&c12(1,r,a+1,b+1));    else return (r[a]<r[b])||(r[a]==r[b]&&wv[a+1]<wv[b+1]);}void sort(int *r,int *a,int *b,int n,int m){    int i;    for(i=0; i<n; i++) wv[i]=r[a[i]];    for(i=0; i<m; i++) wws[i]=0;    for(i=0; i<n; i++) wws[wv[i]]++;    for(i=1; i<m; i++) wws[i]+=wws[i-1];    for(i=n-1; i>=0; i--) b[--wws[wv[i]]]=a[i];    return;}void dc3(int *r,int *sa,int n,int m){    int i,j,*rn=r+n,*san=sa+n,ta=0,tb=(n+1)/3,tbc=0,p;    r[n]=r[n+1]=0;    for(i=0; i<n; i++) if(i%3!=0) wa[tbc++]=i;    sort(r+2,wa,wb,tbc,m);    sort(r+1,wb,wa,tbc,m);    sort(r,wa,wb,tbc,m);    for(p=1,rn[F(wb[0])]=0,i=1; i<tbc; i++)        rn[F(wb[i])]=c0(r,wb[i-1],wb[i])?p-1:p++;    if(p<tbc) dc3(rn,san,tbc,p);    else for(i=0; i<tbc; i++) san[rn[i]]=i;    for(i=0; i<tbc; i++) if(san[i]<tb) wb[ta++]=san[i]*3;    if(n%3==1) wb[ta++]=n-1;    sort(r,wb,wa,ta,m);    for(i=0; i<tbc; i++) wv[wb[i]=G(san[i])]=i;    for(i=0,j=0,p=0; i<ta && j<tbc; p++)        sa[p]=c12(wb[j]%3,r,wa[i],wb[j])?wa[i++]:wb[j++];    for(; i<ta; p++) sa[p]=wa[i++];    for(; j<tbc; p++) sa[p]=wb[j++];    return;}


sa[i]为排名为i的后缀是sa[i],ra[i]是后缀i的排名是ra[i],height[i]为sa[i-1]与sa[i]的最长公共前缀为height[i]。

然后进入正题:

题意:求字符串A,B的最长公共子串

思路:其实很明显把A、B连个字符串合并,然后就是求height[i~n]里面最大的那个,但是要注意的,我们合并完之后遍历height时,符合条件的是i和i-1应该分别是A、B字符串的后缀,不能是同一字符串的后缀!

#include"cstdlib"#include"cstdio"#include"cstring"#include"cmath"#include"queue"#include"algorithm"#include"iostream"using namespace std;#define N 200012int wa[N],wb[N],wv[N],wws[N];int sa[N],ra[N],height[N];char a[N],b[N];int v[N*3];int cmp(int *r,int a,int b,int l){    return r[a]==r[b]&&r[a+l]==r[b+l];}void da(int n,int m){    int i,j,p,*x=wa,*y=wb;    for(i=0;i<m;i++) wws[i]=0;    for(i=0;i<n;i++) wws[x[i]=v[i]]++;    for(i=1;i<m;i++) wws[i]+=wws[i-1];    for(i=n-1;i>=0;i--) sa[--wws[x[i]]]=i;    for(j=1,p=1;p<n;j*=2,m=p)    {        for(i=n-j,p=0;i<n;i++) y[p++]=i;        for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;        for(i=0;i<n;i++) wv[i]=x[y[i]];        for(i=0;i<m;i++) wws[i]=0;        for(i=0;i<n;i++) wws[wv[i]]++;        for(i=1;i<m;i++) wws[i]+=wws[i-1];        for(i=n-1;i>=0;i--) sa[--wws[wv[i]]]=y[i];        for(swap(x,y),p=1,i=1,x[sa[0]]=0;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++;    }    return ;}void getheight(int n){    int i,j,k=0;    for(i=1;i<=n;i++) ra[sa[i]]=i;    for(i=0;i<n;i++)    {        if(k) k--;        j=sa[ra[i]-1];        while(v[i+k]==v[j+k]) k++;        height[ra[i]]=k;    }    return ;}int main(){    while(cin>>a>>b)    {        memset(v,0,sizeof(v));        int i,j=0,ans=0;        for(i=0;a[i];i++) v[j++]=a[i]-'a'+3;        v[j++]=1;  //分割两个字符串        for(i=0;b[i];i++) v[j++]=b[i]-'a'+3;
        v[j]=0;        int len;        len=strlen(a);        da(j+1,30);        getheight(j);        for(i=1;i<=j;i++)        {            if((sa[i]>len&&sa[i-1]<len)||(sa[i]<len&&sa[i-1]>len))  //注意是不同的两个字符串                ans=max(ans,height[i]);        }        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击