●小集训之旅 一
有多大的思想,才有多大的能量。
- 2017.3.27
- 学习内容:Aho-Corasick automaton(AC自动机)(原来不是自动AC机…)
- 算法用途:多模板串的模式匹配问题。
- 算法步骤:
- 用模板串构造Trie树(字典树 or 前缀树);
- 用bfs在Trie树中构建失配指针fail;
- 模式匹配(文本串和模板串进行匹配)
- HDU2222 Keywords Search(本题即为模版…)
- 题
- 一个裸题(入门练手用)(但要注意细节,不然要像我一样调两三节课,555)
#include<cstdio> #include<iostream> #include<cstring> #include<string> #include<queue> #define N 500010 using namespace std; int trie[N][27],f[N],last[N],val[N],n,cnt,ans; char T[2*N],P[55]; void make(int x) //求答案,与刘汝佳的print()相似 { if(!x)return; if(val[x]) ans+=val[x],val[x]=0; make(last[x]); } void add_trie(char *P) //模板串加入Trie树 { int x=0,i=0;char ch; while(P[i]) { ch=P[i]-'a'; if(!trie[x][ch])trie[x][ch]=++cnt; x=trie[x][ch]; i++; } val[x]++; //有重复模板串 } void getfail() //bfs求fail[](and last[]) { queue<int> q; int rt,u,v; for(int i=0;i<26;i++) if(trie[0][i]) q.push(trie[0][i]),f[trie[0][i]]=last[trie[0][i]]=0; while(!q.empty()) { rt=q.front(); q.pop(); for(int i=0;i<26;i++) { u=trie[rt][i]; if(!u)continue; q.push(u);v=f[rt]; while(v&&!trie[v][i])v=f[v]; f[u]=trie[v][i]; last[u]=val[f[u]]?f[u]:last[f[u]]; } } } void Aho_Corasick_automaton(char *T) //匹配 { int x=0,ch; for(int i=0;T[i];i++) { ch=T[i]-'a'; while(x&&!trie[x][ch])x=f[x]; x=trie[x][ch]; if(val[x]) make(x); else if(last[x]) make(last[x]); } } int main() { int cas;scanf("%d",&cas);while(cas--) { memset(trie,0,sizeof(trie)); memset(val,0,sizeof(val)); scanf("%d",&n); ans=0;cnt=0; for(int i=1;i<=n;i++) scanf("%s",P), add_trie(P); getfail(); scanf("%s",T); Aho_Corasick_automaton(T); printf("%d\n",ans); } return 0; } /* 对于多组数据 : trie[],val[] 必须memset f[],last[] 不必memset, 因为(在bfs求fail值时)每个点的f和last值来源于之前的点 所以只需在往队列里加初值时,把对应的点的f和last赋值为0就行了 */
- 如汝佳所言(《训练指南》P216):“把所有不存在的边补上,即把计算失配函数中的语句 if(!u)continue; 改为 if(!u){trie[rt][i]=trie[f[rt]][i];continue;};这样while()便可直接删去。”
void getfail() { queue<int> q; int rt,u,v; for(int i=0;i<26;i++) if(trie[0][i]) q.push(trie[0][i]),f[trie[0][i]]=last[trie[0][i]]=0; while(!q.empty()) { rt=q.front(); q.pop(); for(int i=0;i<26;i++) { u=trie[rt][i]; if(!u){trie[rt][i]=trie[f[rt]][i];continue;}; //** q.push(u);v=f[rt]; f[u]=trie[v][i]; last[u]=val[f[u]]?f[u]:last[f[u]]; } } } void Aho_Corasick_automaton(char *T) { int x=0,ch; for(int i=0;T[i];i++) { ch=T[i]-'a'; x=trie[x][ch]; if(val[x]) make(x); //** else if(last[x]) make(last[x]); } }
Do not go gentle into that good night.
Rage, rage against the dying of the light.
————Dylan Thomas