您的位置:首页 > 其它

hdu 2222 Keywords Search (ac自动机)

2015-09-03 21:20 316 查看
题目: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: