AC自动机模板题,很基础但是很经典,刚接触AC自动机必做题
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<queue>
#include<math.h>
#include<algorithm>
using namespace std;
#define kind 26
#define maxn 10000000
struct node
{
int count;//是否为单词的最后一个结点
node *next[kind];//Trie每个节点的26个子节点
node *fail;//失败指针
};
node *q[maxn];//队列,采用bfs构造失败指针
char keyword[55];//需要查找的子串
char str[maxn];//需要查找的主串
int head,tail;//队列的头尾指针
node *root;
void insert(char *word,node *root)
{
int id,len;
node *p=root,*temp;
len=strlen(word);
for(int i=0;i<len;i++)
{
id=word[i]-'a';
if(p->next[id]==NULL)//改字符节点不存在,加入Trie树中
{
//初始化temp并加入Trie树
temp=new (node);
for(int j=0;j<kind;j++)
temp->next[j]=NULL;
temp->fail=NULL;
temp->count=0;
p->next[id]=temp;
}
p=p->next[id];//指针移向下一层
}
p->count++;//单词结尾,节点count+1做标记
}
void fail(node *root)//构造失败指针
{
head=0;
tail=1;
q[head]=root;
node *temp,*p;
while(head<tail)//bfs构造,Trie树的失败指针
{
//算法类似,这里相当于kmp的next数组
//重点在于匹配失败时,由fail指针回朔到正确的位置
temp=q[head++];
for(int i=0;i<kind;i++)
{
if(temp->next[i])//判断实际存在的节点
{
//root下的第一层节点的失败指针都指向root
if(temp==root)
temp->next[i]->fail=root;
else
{
//依次回朔该节点的父节点的失败指针
//知道某节点的next[i]与该节点相同,
//则把该节点的失败指针指向该next[i]
//节点,若回朔到root都没有找到,则该
//节点的失败指针指向root
p=temp->fail;//temp为节点的父指针
while(p)
{
if(p->next[i])
{
temp->next[i]->fail=p->next[i];
break;
}
p=p->fail;
}
if(!p)
temp->next[i]->fail=root;
}
//每处理一个点,就把它的所有儿子加入队伍
//直到队列为空
q[tail++]=temp->next[i];
}
}
}
}
int query(node *root)//类似于kmp算法
{//以i为主串指针,p为匹配指针
int i,cnt=0,id,len=strlen(str);
node *p=root;
for(i=0;i<len;i++)
{
id=str[i]-'a';
//由失败指针回朔寻找,判断str[i]是否存在于Trie树中
while(p->next[id]==NULL && p!=root)
p=p->fail;
p=p->next[id];//找到后p指向该节点
//指针回为空,则没有找到与之匹配的字符
if(!p)//指针重新回到根结点root,下次从root
p=root;//开始搜索Trie树
node *temp=p;//匹配该节点后,延其失败指针回朔
// 判断其他节点是否匹配
while(temp!=root)//匹配,结束控制
{
if(temp->count>=0)//判断该节点是否被访问
{
//统计出现的单词个数cnt,由于节点不是单词
//结尾时count=0,故cnt+=temp->count;
//只有count>0时才真正统计了单词个数
cnt+=temp->count;
temp->count=-1;//标记已访问
}
else
break;//节点已访问,退出循环
temp=temp->fail;//回朔失败指针继续寻找下一个满足条件的节点
}
}
return cnt;
}
int main()
{
int i,t,n,ans;
scanf("%d",&t);
while(t--)
{
root=new(node);
for(int j=0;j<kind;j++)
root->next[j]=NULL;
root->count=0;
root->fail=NULL;
scanf("%d",&n);
getchar();
for(i=0;i<n;i++)
{
gets(keyword);
insert(keyword,root);
}
fail(root);
gets(str);
ans=query(root);
printf("%d\n",ans);
}
return 0;
}