洛谷P3808 & P3796 AC自動機模板
阿新 • • 發佈:2018-07-17
style sca %d www. ios https front query 字符
題目:P3808:https://www.luogu.org/problemnew/show/P3808
P3796:https://www.luogu.org/problemnew/show/P3796
從這裏學了下AC自動機:http://www.cnblogs.com/cjyyb/p/7196308.html
我的理解大概就是構建一棵由模式串組成的 Trie 樹,然後把文本串一節一節放在上面查找;
失配指針指向的是結尾字母和自己一樣的、Trie 樹上的其他分支,大約就是在找後綴這樣的感覺;
所以文本串每加入一個字符,就在 Trie 樹上查找以這個字符結尾的後綴模式串,所以能找到所有出現過的;
慕名已久的AC自動機原來也挺簡單的嘛!
代碼如下:
P3808:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; int const maxn=1e6+5; int n,cnt; queue<int>q; struct N{ int fail,son[26],end; }AC[maxn]; void build(string s) { int l=s.length(); int nw=0; for(int i=0;i<l;i++) { if(AC[nw].son[s[i]-‘a‘]==0)AC[nw].son[s[i]-‘a‘]=++cnt; nw=AC[nw].son[s[i]-‘a‘]; } AC[nw].end++; } void get_fail() { AC[0].fail=0; for(int i=0;i<26;i++) { if(AC[0].son[i]==0)continue; AC[AC[0].son[i]].fail=0; q.push(AC[0].son[i]); }while(q.size()) { int x=q.front(); q.pop(); for(int i=0;i<26;i++) { if(AC[x].son[i]) { AC[AC[x].son[i]].fail=AC[AC[x].fail].son[i]; q.push(AC[x].son[i]); } else AC[x].son[i]=AC[AC[x].fail].son[i]; } } } int query(string s) { int l=s.length(); int ret=0,nw=0; for(int i=0;i<l;i++) { nw=AC[nw].son[s[i]-‘a‘]; for(int t=nw;t&&AC[t].end!=-1;t=AC[t].fail) { ret+=AC[t].end; AC[t].end=-1; } } return ret; } int main() { scanf("%d",&n); string s; for(int i=1;i<=n;i++) { cin>>s; build(s); } get_fail(); cin>>s; printf("%d\n",query(s)); return 0; }
P3796:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<queue> using namespace std; int const maxn=1e6+5; int n,cnt; queue<int>q; string s[155]; struct N{ int son[26],fail,end; }AC[maxn]; struct P{int num,pos;}ans[155]; bool cmp(P x,P y) { if(x.num==y.num)return x.pos<y.pos; else return x.num>y.num; } void clear(int x) { memset(AC[x].son,0,sizeof AC[x].son); AC[x].fail=0; AC[x].end=0; } void build(string s,int num) { int l=s.length(); int nw=0; for(int i=0;i<l;i++) { if(!AC[nw].son[s[i]-‘a‘])AC[nw].son[s[i]-‘a‘]=++cnt,clear(cnt); nw=AC[nw].son[s[i]-‘a‘]; } AC[nw].end=num; } void get_fail() { while(q.size())q.pop(); AC[0].fail=0; for(int i=0;i<26;i++) { if(AC[0].son[i]==0)continue; AC[AC[0].son[i]].fail=0; q.push(AC[0].son[i]); } while(q.size()) { int x=q.front(); q.pop(); for(int i=0;i<26;i++) { if(AC[x].son[i]) { AC[AC[x].son[i]].fail=AC[AC[x].fail].son[i]; q.push(AC[x].son[i]); } else AC[x].son[i]=AC[AC[x].fail].son[i]; } } } void query(string s) { int l=s.length(); int nw=0; for(int i=0;i<l;i++) { nw=AC[nw].son[s[i]-‘a‘]; for(int t=nw;t/*&&t.end!=-1*/;t=AC[t].fail) { ans[AC[t].end].num++; // AC[t].end=-1; } } } int main() { while(1) { scanf("%d",&n); if(!n)return 0; cnt=0; clear(0); for(int i=1;i<=n;i++) { cin>>s[i]; build(s[i],i); ans[i].pos=i; ans[i].num=0;// } get_fail(); cin>>s[0]; query(s[0]); sort(ans+1,ans+n+1,cmp); printf("%d\n",ans[1].num); cout<<s[ans[1].pos]<<endl; for(int i=2;i<=n;i++) { if(ans[i].num==ans[i-1].num) cout<<s[ans[i].pos]<<endl; else break; } } }
洛谷P3808 & P3796 AC自動機模板