AC自动机

点点圈 提交于 2020-03-18 05:09:44

去年就见到过这个词,不过一直没有去看,不是很理解其中的算法,可能是对kmp还没能够了解透彻。。

一个常见的例子就是给出n个单词,再给出一段包含m个字符的文章,让你找出有多少个单词在文章里出现过。

要搞懂AC自动机,先得有模式树(字典树)TrieKMP模式匹配算法的基础知识。

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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!