zoukankan      html  css  js  c++  java
  • SPOJ1812: LCS2

    【传送门:SPOJ1811&BZOJ2946


    简要题意:

      给出若干个字符串,求出这些字符串的最长公共子串


    题解:

      后缀自动机

      这两道题的区别只是在于一道给出了字符串个数,一个没给,不过也差不多(代码就贴SPOJ的,因为数据范围大一点)

      首先用第一个字符串构造SAM

      然后处理其他的每个串在后缀自动机的每个状态能够匹配的子串最大值

      然后总的来处理所有串在这个状态能够匹配的最小值

      最后将所有状态都枚举一遍,求出其中的最大值就行了


    参考代码:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    struct SAM
    {
        int son[27],fail,dep;
    }tr[210000];int root,cnt,last;
    int a[110000];
    void add(int k)
    {
        int x=a[k];
        int np=++cnt,p=last;
        tr[np].dep=k;
        while(p!=0&&tr[p].son[x]==0) tr[p].son[x]=np,p=tr[p].fail;
        if(p==0) tr[np].fail=root;
        else
        {
            int q=tr[p].son[x];
            if(tr[q].dep==tr[p].dep+1) tr[np].fail=q;
            else
            {
                int nq=++cnt;tr[nq]=tr[q];
                tr[nq].dep=tr[p].dep+1;
                tr[q].fail=tr[np].fail=nq;
                while(p!=0&&tr[p].son[x]==q) tr[p].son[x]=nq,p=tr[p].fail;
            }
        }
        last=np;
    }
    char st[110000];
    int Rsort[210000],sa[210000];
    int d[210000],f[210000];
    int main()
    {
        scanf("%s",st+1);
        int len=strlen(st+1);
        cnt=root=last=1;
        for(int i=1;i<=len;i++) a[i]=st[i]-'a'+1,add(i);
        for(int i=1;i<=cnt;i++) Rsort[tr[i].dep]++;
        for(int i=1;i<=len;i++) Rsort[i]+=Rsort[i-1];
        for(int i=cnt;i>=1;i--) sa[Rsort[tr[i].dep]--]=i;
        memset(f,63,sizeof(f));
        while(scanf("%s",st+1)!=EOF)
        {
            len=strlen(st+1);
            memset(d,0,sizeof(d));
            for(int i=1;i<=len;i++) a[i]=st[i]-'a'+1;
            int p=root,s=0,ans=0;
            for(int i=1;i<=len;i++)
            {
                if(tr[p].son[a[i]]!=0)
                {
                    s++;
                    p=tr[p].son[a[i]];
                }
                else
                {
                    while(p!=0&&tr[p].son[a[i]]==0) p=tr[p].fail;
                    if(p==0) p=root,s=0;
                    else
                    {
                        s=tr[p].dep+1,p=tr[p].son[a[i]];
                    }
                }
                d[p]=max(d[p],s);
            }
            for(int i=cnt;i>=1;i--) d[tr[sa[i]].fail]=min(tr[tr[sa[i]].fail].dep,max(d[tr[sa[i]].fail],d[sa[i]]));
            for(int i=cnt;i>=1;i--) f[sa[i]]=min(f[sa[i]],d[sa[i]]);
        }
        int ans=0;
        for(int i=1;i<=cnt;i++) ans=max(f[i],ans);
        printf("%d
    ",ans);
        return 0;
    }

     

  • 相关阅读:
    [转] DataSet的的几种遍历
    [转] C#实现在Sql Server中存储和读取Word文件 (Not Correct Modified)
    C# 在根据窗体中的表格数据生成word文档时出错
    【剑指offer】堆栈推弹出序列
    kettle于javascript步骤错误处理
    【算法导论】堆排序
    malloc,free简单的实现
    Lichee (六) 优化配置的微内核
    EJBCA于Linux安装在
    【C++】智能指针auto_ptr简单的实现
  • 原文地址:https://www.cnblogs.com/Never-mind/p/8807847.html
Copyright © 2011-2022 走看看