1. 程式人生 > >【SPOJ - LCS2】Longest Common Substring II【SAM】

【SPOJ - LCS2】Longest Common Substring II【SAM】

題意

  求出多個串的最長公共子串。

分析

   剛學SAM想做這個題的話最好先去做一下那道codevs3160。求兩個串的LCS應該怎麼求?把一個串s1建自動機,然後跑另一個串s2,然後找出s2每個字首的最長公共字尾。那麼多個的時候,我們也用這種類似的方法,但是我們求最長公共字尾的時候要求第一個串的。我們把其中一個串建SAM,然後把其他的串都在上面跑,維護兩個值,Max[u]和Min[u]。自動機中每個狀態u的Right存的是結尾集合。那麼對於一個字串,我們可以求出他和自動機中每個狀態的最長公共字尾。然後,我們通過Max[fa[u]]=max(Max[fa[u]],Max[u])來確定左右狀態的最長公共字尾,然後更新Min[o]。

 

下面的程式碼沒有AC,但是我找了好久BUG沒找到··如果有人看完並且找到了bug麻煩跟我說一下萬分感謝!

  

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 
 6 using namespace std;
 7 const int maxn=300000+100;
 8 char s[maxn];
 9 struct state{
10     int len,link;
11 int next[26]; 12 }st[2*maxn]; 13 int n,last,cur,sz; 14 int Min[2*maxn],Max[2*maxn],c[2*maxn]; 15 16 void init(){ 17 sz=1; 18 cur=last=0; 19 st[0].link=-1; 20 st[0].len=0; 21 } 22 23 void build_sam(int c){ 24 cur=sz++; 25 st[cur].len=st[last].len+1; 26 Min[cur]=st[cur].len;
27 int p; 28 for(p=last;p!=-1&&st[p].next[c]==0;p=st[p].link) 29 st[p].next[c]=cur; 30 if(p==-1) 31 st[cur].link=0; 32 else{ 33 int q=st[p].next[c]; 34 if(st[q].len==st[p].len+1) 35 st[cur].link=q; 36 else{ 37 int clone=sz++; 38 st[clone].len=st[p].len+1; 39 Min[clone]=st[clone].len; 40 st[clone].link=st[q].link; 41 for(int i=0;i<26;i++) 42 st[clone].next[i]=st[q].next[i]; 43 for(;p!=-1&&st[p].next[c]==q;p=st[p].link) 44 st[p].next[c]=clone; 45 st[cur].link=st[q].link=clone; 46 } 47 } 48 last=cur; 49 } 50 51 int cmp(int a,int b){ 52 return st[a].len<st[b].len; 53 } 54 55 int main(){ 56 scanf("%s",s); 57 n=strlen(s); 58 init(); 59 60 for(int i=0;i<n;i++) 61 build_sam(s[i]-'a'); 62 for(int i=0;i<sz;i++) 63 c[i]=i; 64 sort(c,c+sz,cmp); 65 66 while(scanf("%s",s)!=EOF){ 67 n=strlen(s); 68 int u=0,len=0; 69 for(int i=0;i<n;i++){ 70 int c=s[i]-'a'; 71 if(u!=-1&&st[u].next[c]==0) 72 u=st[u].link,len=st[u].len; 73 if(u==-1) 74 u=0,len=0; 75 else{ 76 u=st[u].next[c]; 77 len++; 78 Max[u]=max(Max[u],len); 79 } 80 } 81 82 for(int i=sz-1;i>=0;i--){ 83 int o=c[i]; 84 Min[o]=min(Min[o],Max[o]); 85 if(st[o].link!=-1){ 86 Max[st[o].link]=max(Max[st[o].link],Max[o]); 87 } 88 Max[o]=0; 89 } 90 } 91 int ans=0; 92 for(int i=0;i<sz;i++){ 93 ans=max(ans,Min[i]); 94 } 95 printf("%d\n",ans); 96 97 return 0; 98 }
View Code