去年就见到过这个词,不过一直没有去看,不是很理解其中的算法,可能是对kmp还没能够了解透彻。。
一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。
要搞懂AC自动机,先得有模式树(字典树)Trie和KMP模式匹配算法的基础知识。
AC自动机算法分为3步:构造一棵Trie树,构造失败指针和模式匹配过程。
详见:http://www.cppblog.com/mythit/archive/2009/04/21/80633.html (AC自动机算法详解)
贴个模板吧:
hdu 2222 经典ac自动机
# include<stdio.h>
# include<queue>
# include<string.h>
# define MAX 26
using namespace std;
struct Trie{
int count;
struct Trie *next[MAX],*fail;
};
queue<Trie *>q;
char keyword[55];//记录单词
char str[1000005];//记录模式串
Trie *NewTrie()
{
int i;
Trie *temp=new Trie;
temp->count=0;
for(i=0;i<MAX;i++)
temp->next[i]=NULL;
return temp;
}
void Insert(Trie *p,char s[])
{
int i;
Trie *temp=p;
i=0;
while(s[i])
{
if(temp->next[s[i]-'a']==NULL) temp->next[s[i]-'a']=NewTrie();
temp=temp->next[s[i]-'a'];
i++;
}
temp->count++;
}
void bulid_ac_automation(Trie *root)
{
int i;
q.push(root);
root->fail=NULL;
while(!q.empty())
{
Trie *temp=q.front();
q.pop();
Trie *p=NULL;
for(i=0;i<MAX;i++)
{
if(temp->next[i]!=NULL)
{
if(temp==root) temp->next[i]->fail=root;
else
{
p=temp->fail;
while(p!=NULL)
{
if(p->next[i]!=NULL)
{
temp->next[i]->fail=p->next[i];
break;
}//if
p=p->fail;
}//while
if(p==NULL) temp->next[i]->fail=root;
}//else
q.push(temp->next[i]);
}//if
}//for
}//while
}//void
int query(Trie *root)
{
int i,cnt,index,len;
i=0;
cnt=0;
len=strlen(str);
Trie *p=root;
while(str[i])
{
index=str[i]-'a';
while(p->next[index]==NULL && p!=root) p=p->fail;
p=p->next[index];
if(p==NULL) p=root;
Trie *temp=p;
while(temp!=root && temp->count!=-1)
{
cnt+=temp->count;
temp->count=-1;
temp=temp->fail;
}
i++;
}
return cnt;
}
int main()
{
int i,n,ncase,cnt;
Trie *p;
scanf("%d",&ncase);
while(ncase--)
{
p=NewTrie();
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%s",keyword);
Insert(p,keyword);
}
scanf("%s",str);
bulid_ac_automation(p);
cnt=query(p);
printf("%d\n",cnt);
}
return 0;
}
浙公网安备 33010602011771号