1 5 she he say shr her yasherhs
题解:第一道AC自动机啊!!!确实很难理解。不过只要你肯花时间去想就会一点一点的弄懂的。注意,百度的有的代码在查询时得到的结果不对,因为考虑不全。AC自动机就是解决查询给定的多个字符串在文本字符串中出现的个数等问题的。fail指针指向的是和当前字符以及当前字符的前面的连续字符能够重合的其他串,例如:she,he。当我遍历到she中的h时,由于h的fail指向he的h,所以我会去判断he中h是不是字符串,显然不是。当到了she中e时,e的fail指向he中e,此时e是一个串。为什么这样能够找到呢??因为he和she中e和前面连续字符构成串的一样。当文本串出现she肯定就会有he。当然,我只是大概说了一点,这个是说不清楚,因为这种东西需要自己一步一步去理解。理解了就去找该算法的专题来练习。
注意:动态字典树会超时。节点太多。。用静态字典树。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
struct Node
{
	int count;  //判断字符串标记和是否找到了
	Node* fail; //指向和自己后缀匹配的其他字符串
	Node* next[26];
	Node()
	{
		count = 0;
		fail = NULL;
		for(int i = 0;i < 26;i++)
		{
			next[i] = NULL;
		}
	 } 
};
char s[1200000];
Node arr[500005];
Node* root;
int k;
void insert(char* s)
{
	int len = strlen(s);
	Node* p = root;
	for(int i = 0;i < len;i++)
	{
		int x = s[i] - 'a';
		if(p->next[x] == NULL)
		{
			p->next[x] = &arr[k++];
		}
		p = p->next[x];
	}
	
	p->count++;
}
void getFail()
{
	queue<Node*> q;
	q.push(root);
	while(!q.empty())
	{
		Node* p = q.front();
		q.pop();
		for(int i = 0;i < 26;i++)
		{
			if(p->next[i] == NULL)
			{
				continue;
			}
			q.push(p->next[i]);
			Node* t = p->fail;
			while(t)
			{
				if(t->next[i] != NULL)
				{
					p->next[i]->fail = t->next[i];
					break;
				}
				t = t->fail;
			}
			if(t == NULL)
			{
				p->next[i]->fail = root;
			}
		}
	}
}
int acSearch(char* s)
{
	Node* p = root;
	int len = strlen(s);
	int res = 0;
	for(int i = 0;i < len;i++)
	{
		int x = s[i] - 'a';
		while(p != NULL && p->next[x] == NULL)
		{
			p = p->fail;
		}
		if(p == NULL)
		{
			p = root;
			continue;
		}
		Node* t = p->next[x];
		p = p->next[x];
		while(t != NULL && t->count != -1)
		{
			if(t->count != 0)
			{
				res += t->count;
				t->count = -1;
			}
			t = t->fail;
		}
	}
	
	return res;
}
void del(Node*& root)
{
	for(int i = 0;i < 26;i++)
	{
		if(root->next[i] != NULL)
		{
			del(root->next[i]);
		}
	}
	
	delete root;
 } 
int main()
{
	int n;
	cin>>n;
	while(n--)
	{
		root = &arr[0];
		int m;
		k = 1;
		scanf("%d",&m);
		for(int i = 0;i < m;i++)
		{
			scanf("%s",s);
			insert(s);
		}
		getFail();
		scanf("%s",s);
		printf("%d\n",acSearch(s));
		
		for(int i = 0;i < k;i++)
		{
			arr[i].count = 0;
			arr[i].fail = NULL;
			for(int j = 0;j < 26;j++)
			{
				arr[i].next[j] = NULL;
			}
		}
		//del(root);
	}
	
	return 0;
 } 版权声明:本文为博主原创文章,未经博主允许不得转载。
原文:http://blog.csdn.net/wang2534499/article/details/48140705