SPOJ1811最长公共子串问题(后缀自动机)
转载:http://blog.csdn.net/acdreamers/article/details/10746023
题意:给两个串A和B,求这两个串的最长公共子串。
分析:其实本题用后缀数组的DC3已经能很好的解决,这里我们来说说利用后缀自动机如何实现。
对于串A和B,我们先构造出串A的后缀自动机,那么然后用B串去匹配,对于B,我们一位一位地扫描,维护一个ans值,表示从
B串的开始到B[i]的这个子串与A的最长公共子串。
假设现在到B[i-1]的最长公共子串长度为ans,然后我们来看B[i],如果当前节点有B[i]这个孩子,那么直接就len++即可。
如果没有就找一直向前找pre,直到找到有B[i]这个孩子的节点。
1 #include <iostream> 2 #include <string.h> 3 #include <algorithm> 4 #include <stdio.h> 5 6 using namespace std; 7 const int N=250005; 8 9 struct State 10 { 11 State *pre,*go[26]; 12 int step; 13 void clear() 14 { 15 pre=0; 16 step=0; 17 memset(go,0,sizeof(go)); 18 } 19 }*root,*last; 20 21 State statePool[N*2],*cur; 22 23 void init() 24 { 25 cur=statePool; 26 root=last=cur++; 27 root->clear(); 28 } 29 30 void Insert(int w) 31 { 32 State *p=last; 33 State *np=cur++; 34 np->clear(); 35 np->step=p->step+1; 36 while(p&&!p->go[w]) 37 p->go[w]=np,p=p->pre; 38 if(p==0) 39 np->pre=root; 40 else 41 { 42 State *q=p->go[w]; 43 if(p->step+1==q->step) 44 np->pre=q; 45 else 46 { 47 State *nq=cur++; 48 nq->clear(); 49 memcpy(nq->go,q->go,sizeof(q->go)); 50 nq->step=p->step+1; 51 nq->pre=q->pre; 52 q->pre=nq; 53 np->pre=nq; 54 while(p&&p->go[w]==q) 55 p->go[w]=nq, p=p->pre; 56 } 57 } 58 last=np; 59 } 60 61 char A[N],B[N]; 62 63 int main() 64 { 65 int n,m; 66 scanf("%s%s",A,B); 67 n=strlen(A); 68 m=strlen(B); 69 init(); 70 for(int i=0; i<n; i++) 71 Insert(A[i]-'a'); 72 int ans=0,len=0; 73 State *p=root; 74 for(int i=0; i<m; i++) 75 { 76 int x=B[i]-'a'; 77 if(p->go[x]) 78 { 79 len++; 80 p=p->go[x]; 81 } 82 else 83 { 84 while(p&&!p->go[x]) p=p->pre; 85 if(!p) p=root,len=0; 86 else len=p->step+1,p=p->go[x]; 87 } 88 ans=max(ans,len); 89 } 90 printf("%d\n",ans); 91 return 0; 92 }