hdu3065(ac自动机)

病毒侵袭持续中

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4517    Accepted Submission(s): 1609


Problem Description
小t非常感谢大家帮忙解决了他的上一个问题。然而病毒侵袭持续中。在小t的不懈努力下,他发现了网路中的“万恶之源”。这是一个庞大的病毒网站,他有着好多好多的病毒,但是这个网站包含的病毒很奇怪,这些病毒的特征码很短,而且只包含“英文大写字符”。当然小t好想好想为民除害,但是小t从来不打没有准备的战争。知己知彼,百战不殆,小t首先要做的是知道这个病毒网站特征:包含多少不同的病毒,每种病毒出现了多少次。大家能再帮帮他吗?
 

Input
第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。
接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。
在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。
 

Output
按以下格式每行一个,输出每个病毒出现次数。未出现的病毒不需要输出。
病毒特征码: 出现次数
冒号后有一个空格,按病毒特征码的输入顺序进行输出。
 

Sample Input
   
   
   
   
3 AA BB CC ooxxCC%dAAAoen....END
 

Sample Output
   
   
   
   
AA: 2 CC: 1
Hint
Hit: 题目描述中没有被提及的所有情况都应该进行考虑。比如两个病毒特征码可能有相互包含或者有重叠的特征码段。 计数策略也可一定程度上从Sample中推测。
 


本题时要统计母串中模式串出现的次数。在tries的基础上建立前缀指针,从而形成tries图,ac自动机就建立起来了。建议事先写好ac自动机的模板,然后在模板基础上做些改动即可解本题。

 

#include <iostream>
#include<algorithm>
using namespace std;

const int kind = 26;
struct node
{
	node *fail; //失败指针
	node *next[kind]; //Tire每个节点的26个子节点(最多26个字母)
	int count; //是否为该单词的最后一个节点
	node()
	{ //构造函数初始化
		fail=NULL;
		count=0;
		memset(next,NULL,sizeof(next));
	}
}*q[50*1000+10]; //队列,方便用于bfs构造失败指针,大小应依据Tries图节点个数而定

char keyword[1000+5][50+5]; //输入的单词
char str[2000010]; //模式串
int num[1000+10];
int head,tail; //队列的头尾指针

void insert(char *str,node *root,int ind)
//建立一颗以root为根节点的不带前缀指针的字典树
{
	node *p=root;
	int i=0,index;
	while(str[i])
	{
		index=str[i]-'A';
		if(p->next[index]==NULL) 
			p->next[index]=new node();
		p=p->next[index];
		i++;
	}
	p->count=ind;
}


void build_ac_automation(node *root)
//在建好的字典树上添加前缀指针,形成Tries图,即ac自动机
{
	int i;
	root->fail=NULL;
	q[head++]=root;
	while(head!=tail)
	{
		node *temp=q[tail++];
		node *p=NULL;
		for(i=0;i<26;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;
						}
						p=p->fail;
					}
					if(p==NULL) 
						temp->next[i]->fail=root;
				}
				q[head++]=temp->next[i];
			}
		}
	}
}

int query(node *root,int ind)
//有多少种模式串出现在母串str[]中
{
	int i=0,cnt=0,index,len=strlen(str),j;
	node *p=root;
	while(str[i])
	{
		if(str[i]>='A'&&str[i]<='Z')
		{
			index=str[i]-'A';
		//	cout<<index<<endl;
			while(p->next[index]==NULL && p!=root)
				p=p->fail;
			p=p->next[index];
			p=(p==NULL)?root:p;
			node *temp=p;
			while(temp!=root&&temp->count)
			{
				num[temp->count]++;
				temp=temp->fail;
			}
		}
		else 
			p=root;
		i++;
	}
	return cnt;
}

int main()
{
	int n,t,i,m,j,tag;
	while(~scanf("%d",&n))
	{
		head=tail=0;
		node *root=new node();
		getchar();
		for(i=1;i<=n;i++)
		{
			gets(keyword[i]);
			insert(keyword[i],root,i);
		}
		build_ac_automation(root);
		
		memset(num,0,sizeof(num));
		gets(str);
		
		//	cout<<str<<endl;
		query(root,i);
		
		for(i=1;i<=n;i++)
		{
			if(num[i])
				printf("%s: %d\n",keyword[i],num[i]);
		}
		
	}
	return 0;
}


 

你可能感兴趣的:(数据结构,AC自动机)