zoukankan      html  css  js  c++  java
  • POJ 2217 (后缀数组+最长公共子串)

    题目链接http://poj.org/problem?id=2217

    题目大意: 求两个串的最长公共子串,注意子串是连续的,而子序列可以不连续。

    解题思路

    后缀数组解法是这类问题的模板解法。

    对于n个串的最长公共子串,这要把这些串连在一起,中间用"$"这类的特殊符号分隔一下。

    先求后缀数组,再求最长公共前缀,取相邻两个且属于不同串的sa的最大LCP即可。

    原理就是:这样把分属两个串的LCP都跑了一遍,也就是相当于把所有子串走了一遍,

    只不过走这些子串是经过层层预处理过的。

    下面提供一个使用的string模板,稍微稳定点。

    #include "cstring"
    #include "cstdio"
    #include "string"
    #include "iostream"
    using namespace std;
    #define maxn 30000
    struct Suffix
    {
        int r[maxn];
        int sa[maxn],rank[maxn],height[maxn];
        int t[maxn],t2[maxn],c[maxn],n,m;
        void init(string s)
        {
            n=s.size();
            for(int i=0;i<n;i++) r[i]=(int)s[i];
            m=128;
        }
        int cmp(int *r,int a,int b,int l) {return r[a]==r[b]&&r[a+l]==r[b+l];}
        void build()
        {
            int i,k,p,*x=t,*y=t2;
            r[n++]=0;
            for (i=0; i<m; i++) c[i]=0;
            for (i=0; i<n; i++) c[x[i]=r[i]]++;
            for (i=1; i<m; i++) c[i]+=c[i-1];
            for (i=n-1; i>=0; i--) sa[--c[x[i]]]=i;
            for (k=1,p=1; k<n; k*=2,m=p)
            {
                for (p=0,i=n-k; i<n; i++) y[p++]=i;
                for (i=0; i<n; i++) if (sa[i]>=k) y[p++]=sa[i]-k;
                for (i=0; i<m; i++) c[i]=0;
                for (i=0; i<n; i++) c[x[y[i]]]++;
                for (i=1; i<m; i++) c[i]+=c[i-1];
                for (i=n-1; i>=0; i--) sa[--c[x[y[i]]]]=y[i];
                swap(x,y);
                p=1;
                x[sa[0]]=0;
                for (i=1; i<n; i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],k)?p-1:p++;
            }
            n--;
        }
        void LCP()
        {
            int i,j,k=0;
            for (i=1; i<=n; i++) rank[sa[i]]=i;
            for (i=0; i<n; i++)
            {
                if (k) k--;
                j=sa[rank[i]-1];
                while (r[i+k]==r[j+k]) k++;
                height[rank[i]]=k;
            }
        }
        int LCS(string s1,string s2)
        {
            int len=s1.size();
            s1=s1+"$"+s2;
            init(s1);
            build();
            LCP();
            int ans=0;
            for(int i=2;i<=n;i++)
                if((sa[i-1]<len)!=(sa[i]<len)) ans=max(ans,height[i]);
            return ans;
        }
    };
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        ios::sync_with_stdio(false);
        int T;
        string s,t;
        cin>>T;getline(cin,s);
        while(T--)
        {
            getline(cin,s);
            getline(cin,t);
            Suffix a;
            cout<<"Nejdelsi spolecny retezec ma delku "<<a.LCS(s,t)<<"."<<endl;
        }
    }
    13557348 neopenx 2217 Accepted 1060K 32MS C++ 2109B 2014-10-23 10:35:07
  • 相关阅读:
    【Python】自己写日志功能
    shell 笔记
    python 字典,字典嵌套,字典遍历
    python基础 循环,列表,切片,列表增删改查
    Dva_react使用问题总结
    ts_react_test报错解决方法
    如何写好项目规划和方案设计文档 (转)
    script标签引入react环境三个必须cdn文件
    react点击事件对象( react封装过后事件对象 )
    react简书笔记一 环境, git 和 项目 关联
  • 原文地址:https://www.cnblogs.com/neopenx/p/4045194.html
Copyright © 2011-2022 走看看