AC自动机模板题
AC自动机理解要点:
1)fail指针指向的是每个节点,在字典树上和这个节点后缀相同的最长单词,每次都这样匹配,必定不会漏过答案。
2)字典树建立后,会在bfs求fail阶段把字典树变成一个字典树图(不知道理解的对不对),就是把字典树的末尾节点再往下添加一层,并且连接到fail指针指向的相同位子的儿子。
两道模板题和AC代码。
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1000010; char s[maxn],p[maxn]; int trie[maxn][26],cntword[maxn],fail[maxn],cnt=0; int n; void insert(char *s){ int root=0; int si=strlen(s); for(int i=0;i<si;i++) { int Next=s[i]-'a'; if(!trie[root][Next])trie[root][Next]=++cnt; root=trie[root][Next]; } cntword[root]++; } void getfail(){ queue<int >q; for(int i=0;i<26;i++) { if(trie[0][i]){ q.push(trie[0][i]); } } while(!q.empty()) { int now=q.front(); q.pop(); for(int i=0;i<26;i++) { if(trie[now][i]){ fail[trie[now][i]]=trie[fail[now]][i]; q.push(trie[now][i]); }else{ trie[now][i]=trie[fail[now]][i]; } } } } int query(char *s){ int now=0,ans=0; int si=strlen(s); for(int i=0;i<si;i++) { now=trie[now][s[i]-'a']; for(int j=now;j&&cntword[j]!=-1;j=fail[j]) { ans+=cntword[j]; cntword[j]=-1; } } return ans; } int main(){ cin>>n; while(n--) { scanf("%s",p); insert(p); } fail[0]=0; getfail(); scanf("%s",s); cout<<query(s)<<endl; }
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; const int maxn=1000010; char s[maxn],p[maxn]; int trie[maxn][26],cntword[maxn],fail[maxn],cnt=0; int n; int num[maxn]; map<int,string>dio; void insert(char *s){ int root=0; int si=strlen(s); for(int i=0;i<si;i++) { int Next=s[i]-'a'; if(!trie[root][Next])trie[root][Next]=++cnt; root=trie[root][Next]; } dio[root]=s; cntword[root]++; } void getfail(){ queue<int >q; for(int i=0;i<26;i++) { if(trie[0][i]){ q.push(trie[0][i]); } } while(!q.empty()) { int now=q.front(); q.pop(); for(int i=0;i<26;i++) { if(trie[now][i]){ fail[trie[now][i]]=trie[fail[now]][i]; q.push(trie[now][i]); }else{ trie[now][i]=trie[fail[now]][i]; } } } } void query(char *s){ int now=0,ans=0; int si=strlen(s); for(int i=0;i<si;i++) { now=trie[now][s[i]-'a']; for(int j=now;j&&cntword[j]!=-1;j=fail[j]) { //ans+=cntword[j]; if(cntword[j]>0){ num[j]+=cntword[j]; } //cntword[j]=-1; } } } void init(){ clr(trie,0); clr(num,0),clr(cntword,0); dio.clear(); } int main(){ while(scanf("%d",&n),n){ init(); for(int i=1;i<=n;i++) { scanf("%s",p); insert(p); } int p,maxx=0; vector<int >ans; fail[0]=0; getfail(); scanf("%s",s); query(s); for(int i=1;i<=cnt;i++) { if(num[i]>maxx){ maxx=num[i]; ans.clear(); ans.push_back(i); }else if(num[i]==maxx) { ans.push_back(i); } } cout<<maxx<<endl; for(int i=0;i<ans.size();i++) { cout<<dio[ans[i]]<<endl; } } }
——愿为泰山而不骄
qq850874665~~