SPOJ - LCS2 Longest Common Substring II(后缀自动机)
題目鏈接:點擊查看
題目大意:給出n個字符串,求出最長公共子串的長度
題目分析:之前做過了求兩個字符串最長公共子串的長度,相對來說那個題目還算是比較簡單入門的,這個題目就稍微有點加大難度了,其實難度也是在可以接受的范圍之內(nèi),類比于求兩個字符串的最長公共子串,我們其實一樣可以對一個字符串求出SAM,然后讓剩下n-1個字符串在SAM上維護(hù)最大匹配長度,同時在SAM的每個節(jié)點都維護(hù)一個當(dāng)前字符串可以匹配的最大值,顯然最后應(yīng)該維護(hù)每個節(jié)點所有最大值中的最小值作為該節(jié)點可以匹配的最大長度,最后的答案也應(yīng)該是每個節(jié)點可以匹配的最大長度中的最大值了
不過以此延伸出一個問題來,因為每個節(jié)點會通過后綴鏈接和父節(jié)點相連,也就是說如果可以走到一個節(jié)點時,其父節(jié)點也必定是可以到達(dá)的,所以我們需要實時維護(hù)父節(jié)點的最大值,但這也必須保證我們在遍歷SAM時自底向上遍歷才行,為了解決這個問題,我們可以在構(gòu)造出SAM后進(jìn)行拓?fù)渑判?#xff0c;其實這個拓?fù)渑判蜻€是相對簡單的,因為只需要對于每個節(jié)點的len進(jìn)行排序就好了,利用桶排序就可以完成,在更新時按照拓?fù)湫虻怪戮秃昧?/p>
代碼:
#include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<set> #include<sstream> #include<unordered_map> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e5+100;char s[N];int tot=1,last=1,id[N<<1],tong[N<<1],mmax[N<<1],mmin[N<<1];struct Node {int ch[26];int fa,len; }st[N<<1];void add(int x) {int p=last,np=last=++tot;st[np].len=st[p].len+1;while(p&&!st[p].ch[x])st[p].ch[x]=np,p=st[p].fa;if(!p)st[np].fa=1;else{int q=st[p].ch[x];if(st[p].len+1==st[q].len)st[np].fa=q;else{int nq=++tot;st[nq]=st[q]; st[nq].len=st[p].len+1;st[q].fa=st[np].fa=nq;while(p&&st[p].ch[x]==q)st[p].ch[x]=nq,p=st[p].fa;//向上把所有q都替換成nq}} }void radix_sort() {for(int i=1;i<=tot;i++)tong[st[i].len]++;for(int i=1;i<=tot;i++)tong[i]+=tong[i-1];for(int i=1;i<=tot;i++)id[tong[st[i].len]--]=i; }void solve() {memset(mmax,0,sizeof(mmax));int len=strlen(s),k=1,cnt=0;for(int i=0;i<len;i++){int to=s[i]-'a';if(st[k].ch[to]){cnt++;k=st[k].ch[to];mmax[k]=max(mmax[k],cnt);}else{while(k&&!st[k].ch[to])k=st[k].fa;if(k){cnt=st[k].len+1;k=st[k].ch[to];mmax[k]=max(mmax[k],cnt);}else{cnt=0;k=1;}}}//以上是完成求兩個字符串的最長公共子串的基操for(int i=tot;i>=1;i--){int cur=id[i],fa=st[cur].fa;mmax[fa]=max(mmax[fa],min(st[fa].len,mmax[cur]));//維護(hù)父節(jié)點的最大值mmin[cur]=min(mmin[cur],mmax[cur]);//維護(hù)每個節(jié)點的最小值} }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);scanf("%s",s);int len=strlen(s);for(int i=0;i<len;i++)add(s[i]-'a');radix_sort();for(int i=1;i<=tot;i++)mmin[i]=st[i].len;while(scanf("%s",s)!=EOF)solve();int ans=0;for(int i=1;i<=tot;i++)ans=max(ans,mmin[i]);printf("%d\n",ans);return 0; }?
總結(jié)
以上是生活随笔為你收集整理的SPOJ - LCS2 Longest Common Substring II(后缀自动机)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SPOJ - LCS Longest C
- 下一篇: SPOJ - NSUBSTR Subst