题目:http://acm.hdu.edu.cn/showproblem.php?pid=2222
题意:求有多少个模式串出现在文本串里面。
分析:ac自动机模版题。说一下自己对ac自动机的理解,①fail指针指向的位置:父亲节点的fail指针指向的位置的一个孩子节点的位置,并且这个孩子节点所代表的字符与当前位置的字符相同。②fail指针的作用:利用fail指针可以在trie中找到一个最长前缀与当前串的后缀匹配。③对ac自动机的改造:把不存在的孩子节点“补上”,由于该节点并不在trie中,匹配到当前该节点位置的时候可以直接跳过,跳到该节点的fail指针指向的位置。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int maxn = 5e5+6;
const int kd = 26;
struct Trie
{
int son[maxn][kd],end[maxn],fail[maxn];
int root,cnt;
int newnode()
{
end[cnt]=0;
fill(son[cnt],son[cnt]+kd,-1);
return cnt++;
}
void Init()
{
cnt=0;
root=newnode();
}
void Insert(char str[])
{
int index,i,now=root;
for(i=0;str[i];i++)
{
index=str[i]-'a';
if(son[now][index]==-1)
son[now][index]=newnode();
now=son[now][index];
}
++end[now];
}
void findfail()
{
queue <int > q;
int i,j,now;
fail[root]=root;
for(i=0;i<kd;i++)
if(son[root][i]==-1)
son[root][i]=root;
else
{
fail[son[root][i]]=root;
q.push(son[root][i]);
}
while(!q.empty())
{
now=q.front();
q.pop();
for(i=0;i<kd;i++)
if(son[now][i]==-1)
son[now][i]=son[fail[now]][i];
else
{
fail[son[now][i]]=son[fail[now]][i];
q.push(son[now][i]);
}
}
}
int Query(char str[])
{
int temp,i,now=root,index,ret=0;
for(i=0;str[i];i++)
{
index=str[i]-'a';
now=son[now][index];
temp=now;
while(temp!=root)
{
ret+=end[temp];
end[temp]=0;
temp=fail[temp];
}
}
return ret;
}
}ac;
char T[maxn<<1],M[maxn];
int main()
{
int ncase,n;
scanf("%d",&ncase);
while(ncase--)
{
ac.Init();
scanf("%d",&n);
while(n--)
{
scanf("%s",M);
ac.Insert(M);
}
ac.findfail();
scanf("%s",T);
printf("%d\n",ac.Query(T));
}
return 0;
}