hdu2222(AC自动机模板)

解题思路:AC自动机模板题,没什么好说的。关于题目中一些要注意的问题详见代码注释,代码复杂度为O(n),n为字符串长度

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=500009;
struct node
{
	char c;
	int next[26],fg,fail;
}s[MAXN];
int cnt,ans;
char tp[60],t[1000009];
queue<int> q;
void make_tire()//建立字典树 
{
	int l=strlen(tp);
	int r=0;
	for(int i=0;i<l;i++)
	{
		if(s[r].next[tp[i]-'a']==-1)
		{
			s[cnt].c=tp[i];
			s[cnt].fg=0;
			s[cnt].fail=-1;
			memset(s[cnt].next,-1,sizeof(s[cnt].next));
			s[r].next[tp[i]-'a']=cnt++;
		}
		r=s[r].next[tp[i]-'a'];
	}
	s[r].fg++;
}
void make_ac()//建立ac自动机 
{
	int a,p,r;
	q.push(0);
	while(!q.empty())
	{
		r=q.front();
		q.pop();
		for(int i=0;i<26;i++)
		{
			if(s[r].next[i]==-1) continue;
			a=s[r].next[i];
			q.push(a);
			p=s[r].fail;
			while(p!=-1)
			{
				if(s[p].next[i]!=-1)
				{
					s[a].fail=s[p].next[i];
					break;
				}
				p=s[p].fail;
			}
			if(p==-1)
			{
				s[a].fail=0;
			}
		}
	}
}
void query()
{
	int l=strlen(t),temp;
	int r=0,v,f;
	for(int i=0;i<l;i++)
	{
		v=t[i]-'a';
		if(s[r].next[v]!=-1)
		{
			r=s[r].next[v];
		}else
		{
			f=s[r].fail;
			while(f!=-1)
			{
				if(s[f].next[v]!=-1)
				{
					r=s[f].next[v];
					break;
				}
				f=s[f].fail;
			}
			if(f==-1) r=0;
		}
		temp=r;
		while(temp!=0)//这是防止出现一个问题,比如she,和he,对于she来说,没有这部,只会统计she,不会统计he  
		{
			if(s[temp].fg>=0) 
			{
				ans+=s[temp].fg;
				s[temp].fg=-1;//表示这个关键字已经访问过了,已经纳入统计,以后无需再访问。没有会超时的!!!! 
			}else
			break;
			temp=s[temp].fail; 		
		}
	}
}
int main()
{
	//freopen("t.txt","r",stdin);
	int T,n;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&n);
		memset(s[0].next,-1,sizeof(s[0].next));
		s[0].fg=0;
		s[0].fail=-1;
		cnt=1;
		getchar();
		for(int i=0;i<n;i++)
		{
			gets(tp);
			//printf("%s\n",tp);
			make_tire();
		}
		while(!q.empty()) q.pop();
		make_ac();
		gets(t);
		ans=0;
		query();
		printf("%d\n",ans);
	}
	return 0;	
} 

猜你喜欢

转载自blog.csdn.net/qq_39861441/article/details/87921195