poj3294 后缀数组

后缀数组多个字符串问题。 

先求出height[]数组,然后二分求最大的长度。

但是条件需要改变。如果出现次数大于一般那就满足。然后就要解决如何判断那一段属于其中一个字符串。

所以先处理出长度。并且不断标记,如果在长度其中,将那个长度标记。那就不会出现自己与自己的相同情况了。

RE了很多次,字符串输入的时候同时存入整数,防止过大可能使字符串出现问题。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<string>
#include<map>
#define LL long long
using namespace std;
#define maxn 1110000
int max(int x,int y)
{return x>y?x:y;}
int min(int x,int y)
{return x<y?x:y;}
int wa[maxn],wb[maxn],wv[maxn],WS[maxn];
int vex[maxn],size,vis[120],pre[maxn],cou;//vex存每一段的长度 size表示个数 pre存满足条件的开始位置 cou存满足的个数
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(int *r,int *sa,int n,int m)
{
    int i,j,p,*x=wa,*y=wb,*t;
    for(i=0;i<m;i++) WS[i]=0;
    for(i=0;i<n;i++) WS[x[i]=r[i]]++;
    for(i=1;i<m;i++) WS[i]+=WS[i-1];
    for(i=n-1;i>=0;i--) sa[--WS[x[i]]]=i;
    for(j=1,p=1;p<n;j*=2,m=p)
    {
        for(p=0,i=n-j;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++) WS[i]=0;
        for(i=0;i<n;i++) WS[wv[i]]++;
        for(i=1;i<m;i++) WS[i]+=WS[i-1];
        for(i=n-1;i>=0;i--) sa[--WS[wv[i]]]=y[i];
        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
    return;
}
int Rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
    int i,j,k=0;
    for(i=1;i<=n;i++) Rank[sa[i]]=i;
    for(i=0;i<n;height[Rank[i++]]=k)
        for(k?k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);
    return;
}
int r[maxn],sa[maxn];
int ok(int x,int n,int k)
{
    cou=0;
    int i,j,ret=0;
    memset(vis,0,sizeof(vis));
    for(i=1;i<=n;i++)
    {
        if(height[i]>=x)
        {
            for(j=1;j<size;j++)
            {
                if(sa[i]>vex[j-1]&&sa[i]<vex[j])//由于自己添加的并不会相同 所以只要满足在中间位置就可以
                {
                    if(!vis[j])//如果满足就标记掉那个位置
                    {
                        vis[j]=1;
                        ret++;
                    }
                }
                if(sa[i-1]>vex[j-1]&&sa[i-1]<vex[j])
                {
                    if(!vis[j])
                    {
                        vis[j]=1;
                        ret++;
                    }
                }
            }
        }
        else
        {
            if(ret>k)
            {
                pre[cou++]=sa[i-1];

            }
            ret=0;
            memset(vis,0,sizeof(vis));
        }
    }
    if(ret>k)
    {
        pre[cou++]=sa[n];
    }
    if(cou>0)//表面有满足条件的
        return 1;
    return 0;
}
char s[maxn],c[maxn];
int main()
{
    int i,n,ff=0,fl;
    while(cin>>n)
    {
        if(!n)break;
        size=1;
        int len=0;
        int num=123;
        for(i=0;i<n;i++)
        {
            scanf("%s",c);
            int fl=strlen(c);
            for(int p=0;p<fl;p++)
            {
                r[len]=c[p];//修改了此处 过了 之前是先存在s[]中 但是会出现问题 因为100多可能字符有问题
                s[len++]=c[p];
            }
            vex[size++]=len;
            r[len]=num;
            s[len++]=num++;
        }
        len--;
        int j=len;
        r[j]=0;
        da(r,sa,j+1,250);
        calheight(r,sa,j);
        int left,right,mid,ans=-1;
        left=1,right=j,cou=0;
        while(left<=right)
        {
            mid=(left+right)/2;
            if(ok(mid,j,n/2))
            {
                fl=cou;
                ans=mid;
                left=mid+1;
            }
            else right=mid-1;
        }
        /*for(i=1;i<=j;i++)
        printf("%d ",height[i]);
        printf("\n");*/
        if(ff)
            printf("\n");
        else ff=1;
        if(ans<=1)
        {
            printf("?\n");
            continue;
        }
        //printf("%d\n",ans);
        for(i=0;i<fl;i++)
        {
            for(j=0;j<ans;j++)
            {
                printf("%c",s[pre[i]+j]);
            }
            printf("\n");
        }
    }
}
/*
5
abcdef
bcdea
hzbcde
bcdyz
acxq
*/

 

posted @ 2015-09-10 21:59  sweat123  阅读(129)  评论(0编辑  收藏  举报