zoukankan      html  css  js  c++  java
  • poj 3294 Life Forms(后缀数组)

    题意:给你最多100个字符串,求最长的且是一半以上的字符串的公共子串,如果有多个,按字典序输出。

    思路:先把各个串拼起来,中间加上一个之前未出现过的字符,然后求后缀。然后根据h数组和sa数组,求出最长的公共串。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using std::sort;
    #define V 220000
    int r[V],sa[V],h[V],a[V],b[V],X[V],Y[V];
    int acl[120],len[110],tot,mark[V],mark_len,be[V],m[110],max_len;
    char s[V],out1[V],out2[V];
    void calh(int n)
    {
        int i,j,k=0;
        for(i=1; i<=n; i++)r[sa[i]]=i;
        for(i=0; i<n; h[r[i++]]=k)
            for(k? k-- :0,j=sa[r[i]-1];a[i+k]==a[j+k];k++);
    }
    bool cmp(int *r,int a,int b,int le)
    {
        return (r[a]==r[b]&&r[a+le]==r[b+le]);
    }
    void suffix(int n,int m=128)
    {
        int i,j,*x=X,*y=Y,*t,p;
        for(i=0;i<m;i++)b[i]=0;
        for(i=0;i<n;i++)b[x[i]=a[i]]++;
        for(i=1;i<m;i++)b[i]+=b[i-1];
        for(i=n-1;i>=0;i--)sa[--b[x[i]]]=i;
        for(j=1,p=1;p<n;m=p,j<<=1)
        {
            p=0;
            for(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<m;i++)b[i]=0;
            for(i=0;  i<n;i++)b[x[y[i]]]++;
            for(i=1;  i<m;i++)b[i]+=b[i-1];
            for(i=n-1;i>=0;i--)sa[--b[x[y[i]]]]=y[i];
            for(t=x,x=y,y=t,x[sa[0]]=0,i=1,p=1;i<n;i++)
                x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
        }
        calh(n-1);
    }
    void judge(int n)//先预处理每个sa属于哪个串
    {
        int i,j,k;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=tot;j++)
            {
                if(sa[i]==len[j]){
                    be[i]=0;
                    break;
                }
                if(sa[i]<len[j]){
                    be[i]=j;
                    break;
                }
            }
        }
    }
    int mm[110];
    int getmin(int s)//排序得到当前最长的公共串长度
    {
        for(int i=1;i<=tot;i++)mm[i]=m[i];
        sort(mm+1,mm+1+tot);
        return mm[tot+1-s];
    }
    void solve(int n)
    {
        int cou=tot/2+1,cur=0,cur_len=0,i,j;//cou表示至少需要的串的数量,cur表示目前的子串所在的串的数量,cur_len表示目前子串的长度
        judge(n);
        memset(m,0,sizeof(m));//m表示各个串包含的子串的长度
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=tot;j++)if(m[j]>h[i])//更新mi
                m[j]=h[i];
            if(h[i]<max_len){
                cur=0;continue;
            }
            if(h[i]>m[be[i]]){
                if(m[be[i]]==0||m[be[i]]<max_len)cur++;
                m[be[i]]=h[i];
            }
            if(h[i]>m[be[i-1]]){
                if(m[be[i-1]]==0||m[be[i-1]]<max_len)cur++;
                m[be[i-1]]=h[i];
            }
            if(cur>=cou){
                cur_len=getmin(cou);
                if(cur_len>max_len)
                {
                    mark_len=1;
                    mark[0]=sa[i];
                    max_len=cur_len;
                }
                else if(cur_len==max_len)
                    mark[mark_len++]=sa[i];
            }
        }
    }
    int main()
    {
        int i,j,k,t,n;
        for(i=1;i<=96;i++)acl[i]=i;
        for(i=97;i<=110;i++)acl[i]=i+26;
        while(scanf("%d",&t)!=-1&&t)
        {
           len[0]=-1;
           for(i=1;i<=t;i++)
           {
              scanf("%s",s+len[i-1]+1);
              len[i]=strlen(s);
              s[len[i]]=acl[i];
           }
           s[len[t]]=0;
           n=strlen(s);
           for(i=0;i<n;i++)a[i]=s[i];
           a[n]=0;
           suffix(n+1);
           mark_len=0;max_len=0;tot=t;
           solve(n);
           if(max_len==0)
                printf("?
    
    ");
           else{
               strcpy(out1,s+mark[0]);
               out1[max_len]=0;
               puts(out1);
               for(i=1;i<mark_len;i++){
                    strcpy(out2,s+mark[i]);
                    out2[max_len]=0;
                    if(strcmp(out1,out2)==0)continue;
                    strcpy(out1,out2);
                    puts(out1);
               }
               puts("");
           }
        }
        return 0;
    }
    


  • 相关阅读:
    go golang 代码记录
    ERROR org.apache.hadoop.yarn.server.resourcemanager.ResourceManager: RECEIVED SIGNAL 15
    hbase启动之后master和regionserver相继自动断掉
    Native memory allocation (malloc) failed to allocate 32744 bytes for ChunkPool::allocate
    虚拟机中二次安装cdh重新启动hadoop集群报错
    cdh在虚拟机中二次安装时无法选择之前管理的主机
    sqoop生成与关系数据库表结构对应的hive表结构,但在hive却找不到table
    Sqoop将hive数据导出到MySQL中文乱码了怎么办?
    idea通过maven打jar包不成功或无法加载主类或打成功也找不到jar包
    一个牛公司的关于oracle数据的面试题
  • 原文地址:https://www.cnblogs.com/jiangu66/p/3249171.html
Copyright © 2011-2022 走看看