●小集训之旅 一
有多大的思想,才有多大的能量。
- 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

浙公网安备 33010602011771号