前言


为了写一个AC自动机模板,参考了n多blog的代码,不料所有代码都如出一辙。本想写一个风格独特的模板,至少与其他人的不一样,但是因为思路上的先入为主等原因,还真没写出什么花样,跟网上其他的模板也没什么不同。

题目大意


给出n个模式串和一个被匹配串,问有多少个模式串可以成功匹配。

思路


裸AC自动机,模板题。思路见代码。

代码


#include<iostream>
#include<stdio.h>
using namespace std;

#define T_SIZE 1000000
#define P_SIZE 50
#define TOTAL_P 10000

struct trie
//利用结构体来封装字典树的节点。
{
	trie* next[26];
	trie* fail;
	int num;
	trie()
	//构造函数。
	{
		for(int i=0;i<26;i++)
			next[i]=NULL;
		fail=NULL;
		num=0;
	}
};

char T[T_SIZE+1];
char P[P_SIZE+1];
trie* q[TOTAL_P*P_SIZE];

void insert(trie* root,char* s)
//将字符串s所表示的单词插入到字典树中。
{
	trie* p=root;
	for(int i=0;s[i]!='\0';i++)
	{
		if(p->next[s[i]-'a']==NULL)
			p->next[s[i]-'a']=new trie;
		p=p->next[s[i]-'a'];
	}
	p->num++;
}

void  build_ac_automation(trie* root)
//利用广搜构建失败指针 
{
	int head=0,tail=0;
	q[tail++]=root;
	while(head!=tail)
	{
		trie* front=q[head++];
		//front为队头元素 
		for(int i=0;i<26;i++)
			if(front->next[i]!=NULL)
			//遍历队头元素的子节点 
			{
				trie* p=front->fail;
				while(p!=NULL)
				//只有根节点的失败指针为NULL 
				{
					if(p->next[i]!=NULL)
					//顺着失败指针往回走,直至某个节点,其拥有一个字母为'a'+i的子节点。 
					{
						front->next[i]->fail=p->next[i];
						break;
					}
					p=p->fail;
				}
				if(p==NULL)
				//p==NULL说明顺着失败指针往回走的过程中没有找到合适的节点,所以将失败指针指向根节点。 
					front->next[i]->fail=root;
				q[tail++]=front->next[i];
			}
	}
}

int ac_find(trie* root,char* T)
{
	trie* p=root;
	int sum=0;
	for(int i=0,len=strlen(T);i<len;i++)
	{
		while(p->next[T[i]-'a']==NULL&&p!=root)
		//若当前节点的没有一个字符为T[i]的儿子且当前节点不是根节点
		//通俗的讲,就是顺着失败指针往回走,直至找到合适的节点或根节点为止。 
			p=p->fail;
		if(p->next[T[i]-'a']!=NULL)
		//p->next[T[i]-'a']==NULL说明没找到合适的节点,p指针指在根节点上。
			p=p->next[T[i]-'a']; 
		trie* temp=p;
		while(temp!=root&&temp->num!=-1)
		//顺着失败指针往回走,一直到根节点。 
		{
			sum+=temp->num;
			//若当前节点的num不为0,则说明以当前节点字母结尾的单词出现过一次。
			//此单词是以上一次循环的节点单词为结尾的单词的子集。 
			temp->num=-1;
			//标记num为-1,避免重复计算。 
			temp=temp->fail;
		}
	}
	return sum;
}

int main()
{
	int t;
	for(scanf("%d",&t);t>0;t--)
	{
		trie* root=new trie;
		int n;
		scanf("%d",&n);
		getchar();
		for(int i=0;i<n;i++)
		{
			gets(P);
			insert(root,P);
		}
		build_ac_automation(root);
		gets(T);
		printf("%d\n",ac_find(root,T));
	}
}