题目:http://poj.org/problem?id=2217
首先解释,DP中的最长公共子序列和此处的最长公共子串区别-------------------序列可以是不连续的,但是子串是连续的
其次,LCP,lcp[i]就是lcp[rank[i]]和lcp[rank[i]+1]的最长公共前缀,那么把两个字符串接起来,然后找最长的lcp,就是答案
思路还是比较清晰的
上代码:
- /*******************************************************/
- //poj 2217 lcp+sa by Pilgrim
- //最长公共子串---注意与动态规划的最长公共子序列不同
- //2014.4.2
- /******************************************************/
- #include <string>
- #include <cstring>
- #include <cstdio>
- #include <algorithm>
- #include <iostream>
- #include <cstdlib>
- #include <vector>
- #define MAXN 10010
- #define INF 0x80000000
- //0x7fffffff
- //0x80000000
- using namespace std;
- int n,k;//n=strlen(s);
- int Rank[MAXN];
- int tmp[MAXN];
- /*使用Rank对sa排序*/
- bool cmpSa(int i, int j)
- {
- if(Rank[i] != Rank[j])return Rank[i] < Rank[j];
- else
- { /*下面的Rank[t],已经是以t开头长度小于等于k/2的,
- sa[i]的名次,只是以i开头的后缀,而长度不同*/
- int ri = i+k <=n? Rank[i+k]:-1;
- int rj = j+k <= n ? Rank[j+k]:-1;
- return ri <rj;
- }
- }
- /*计算SA*/
- void con_sa(char *s, int *sa)
- {
- /*n=strlen(s); 必要时注明*/
- /*初始化sa和rank保证两点
- 1、Rank[i]表示下标为i的是第几大,必须表示出相对大小,可以直接用字符代表其大小
- 2、sa[1...n]值为1..n*/
- for(int i=0;i<=n;i++){
- sa[i]=i;Rank[i] = i < n?s[i]:-1;
- }
- /*利用长度为k的字符串对长度为2*k的字符串排序*/
- for(k=1;k<=n;k*=2)/*注意此代码中k是全局变量 别乱用,循环必须从1开始,因为0*2=0*/
- {
- sort(sa,sa+n+1,cmpSa);
- tmp[sa[0]] = 0; /*此时tmp只是暂存rank*/
- for(int i=1;i<=n;i++){
- tmp[sa[i]] = tmp[sa[i-1]] +(cmpSa(sa[i-1],sa[i])?1:0);
- /*这一句很关键,等号右侧的sa[i]在此循环里表示第i大的长度小于等于k/2的字符串,
- 从而求出第i大的长度小于等于k的字符串的sa[i]*/
- }
- for(int i=0;i<=n;i++){
- Rank[i] = tmp[i];
- }
- }
- }
- void construct_lcp(char *s,int *sa,int *lcp)
- {
- //n=strlen(s);
- for(int i=0; i<=n; i++)Rank[sa[i]]=i;
- int h=0;
- lcp[0]=0;
- for(int i=0;i<n;i++)
- {
- int j=sa[Rank[i]-1];
- if(h>0)h--;
- for(; j+h<n && i+h<n; h++)
- {
- if(s[j+h]!=s[i+h])break;
- }
- lcp[Rank[i]-1]=h;
- }
- }
- int main()
- {
- int sa[MAXN],lcp[MAXN];
- char s[MAXN],t[MAXN];
- char c;
- int ncase,mmax,len,leng;
- while(scanf("%d",&ncase)!=EOF)
- {
- while(ncase--)
- {
- mmax =0;
- while((c=getchar())==' '|| c=='\n');
- s[0]=c;
- int tt=1;
- while((c=getchar()) != '\n')
- {
- s[tt++]=c;
- }
- s[tt]='\0';
- while((c=getchar())==' '|| c=='\n');
- t[0]=c;
- tt=1;
- while((c=getchar()) != '\n')
- {
- t[tt++]=c;
- }
- t[tt]='\0';
- len=strlen(s);
- leng =len+1+strlen(t);
- strcpy(s+len+1,t);
- ///
- //for(int i=0;i<leng;i++)
- // putchar(s[i]);
- //putchar('\n');
- n=leng;
- con_sa(s,sa);
- construct_lcp(s,sa,lcp);
- for(int i=0;i<leng;i++)
- {
- if((sa[i]<len) != (sa[i+1]<len))
- mmax=max(mmax,lcp[i]);
- }
- printf("Nejdelsi spolecny retezec ma delku %d.\n",mmax);
- }
- }
- return 0;
- }