LCP poj 2217 尋找最長公共子串
阿新 • • 發佈:2019-01-10
題目: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; }