hdu 2222 Keywords Search 经典AC自动机入门题

时间:2021-09-23 22:48:41

刚学的AC自动机,代码写的不是很好,还是有一定的收获

可以参考一下这个博客http://www.cppblog.com/mythit/archive/2009/04/21/80633.html

代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define maxn 1001000
int cur;
struct node
{
int fail;
int next[28];
int count;
void init()
{
count=0;
fail=0;
memset(next,-1,sizeof(next));
}
}trie[maxn];
int queue[maxn];
void creat_init()
{
cur=1;
trie[0].init();
}
void insert_trie(char *s)
{
int len=strlen(s);
int p=0;
for(int i=0; i<len; i++)
{
int x=s[i]-'a';
if(trie[p].next[x]==-1)
{
trie[cur].init();
trie[p].next[x]=cur++;
}
p=trie[p].next[x];
}
trie[p].count++;
}
void creat_fail()
{
int qian=0,hou=0;
int i;
int head,head_fail;
for(i=0; i<26; i++)
{
if(trie[0].next[i]!=-1)//先考虑根节点,和根节点相连的都入队
queue[qian++]=trie[0].next[i];
}
while(qian!=hou)
{
head=queue[hou++];
for(i=0; i<26; i++)
{
if(trie[head].next[i]!=-1)
{
queue[qian++]=trie[head].next[i];
head_fail=trie[head].fail;
while(head_fail>0&&trie[head_fail].next[i]==-1)//当失配指针不为root时一直循环直到找到一个节点的儿子是i值或到了root
head_fail=trie[head_fail].fail;
if(trie[head_fail].next[i]!=-1)//如果当前节点有儿子的话记录下来备用
head_fail=trie[head_fail].next[i];
trie[trie[head].next[i]].fail=head_fail;//使当前节点的失配指针指向刚才记录的节点完成失配指针的寻找构造。
}
}
}
}
int Find(char *s)
{
int num=0;
int len=strlen(s);
int i,x,p=0,q;
for(i=0; i<len; i++)
{
x=s[i]-'a';
while(p>0&&trie[p].next[x]==-1)
p=trie[p].fail;//一直寻找失配指针
if(trie[p].next[x]!=-1)
{
p=trie[p].next[x];
q=p;
while(q>0&&trie[q].count!=-1)//q>0表示还没到root,count != -1表示指针前还有单词
{
num+=trie[q].count;
trie[q].count=-1;//不重复计算,注意这里很重要
q=trie[q].fail;
}
}
}
return num;
}
int main()
{
int t, n;
char str[maxn],ss[100];
scanf("%d",&t);
while(t--)
{
creat_init();
scanf("%d", &n);
for(int i=0; i<n; i++)
{
scanf("%s",ss);
insert_trie(ss);
}
creat_fail();
scanf("%s",str);
printf("%d\n", Find(str));
}
return 0;
}