Problem Description
In the modern time, Search engine came into the life of everybody like Google, Baidu, etc.
Wiskey also wants to bring this feature to his image retrieval system.
Every image have a long description, when users type some keywords to find the image, the system will match the keywords with description of image and show the image which the most keywords be matched.
To simplify the problem, giving you a description of image, and some keywords, you should tell me how many keywords will be match.
Input
First line will contain one integer means how many cases will follow by.
Each case will contain two integers N means the number of keywords and N keywords follow. (N <= 10000)
Each keyword will only contains characters ‘a’-‘z’, and the length will be not longer than 50.
The last line is the description, and the length will be not longer than 1000000.
Output
Print how many keywords are contained in the description.
Sample Input
1
5
she
he
say
shr
her
yasherhs
Sample Output
3
//第一次接触AC自动机就参考了讨论区里一个大神的代码 然后根据自己的理解写出了这个代码
#include<iostream>
#include<stdio.h>
#include<queue>
#include<string.h>
#include<string>
using namespace std;
struct Tree
{
int isword;
struct Tree *next[26];
struct Tree *fail;
}*root;
char text[1000010],pattern[60];//text文本串pattern模式串
int cnt =0;
void Insert(char ch[])
{
Tree *p = root;
int i =0;
while(ch[i])
{
int indx = ch[i] -'a';
if(p->next[indx]==NULL)
{
Tree *q = (Tree *)malloc(sizeof(Tree));
memset(q->next,0,sizeof(q->next));
q->isword = 0;
p->fail = NULL;
p->next[indx] = q;
}
p = p->next[indx];
i++;
}
p->isword++;
}
void build_AC_automaton()//构建AC自动机
{
queue<Tree *> pq;
Tree *p = root;
p->fail = NULL;//根节点的失败指针指向自己或者为空
pq.push(p);
while(!pq.empty())
{
p = pq.front();
pq.pop();
for(int i =0;i<26;i++)
{
if(p->next[i]!=NULL)
{
if(p==root)//单独处理第二层 让第二层的失败指针指向root
{
p->next[i]->fail = root;
}
else
{
Tree *q = p->fail;
while(q)
{
if(q->next[i])
{
p->next[i]->fail = q->next[i];
break;
}
q = q->fail;//一直向上根据父节点的失败指针查找 一直找到根节点
}
if(q==NULL)
{
p->next[i]->fail = root;//如果此时整棵树都没有字母c了 呢就让该节点的失败指针指向root
}
}
pq.push(p->next[i]);
}
}
}
}
void find_in_AC_automaton()
{
Tree *p = root;
int indx = 0;
while(text[indx])
{
int lowindx = text[indx] -'a';
while(p->next[lowindx]==NULL&&p!=root) p = p->fail;
p = p->next[lowindx];
if(p==NULL)
p = root;
Tree *q = p;
while(q&&q->isword!=-1)
{
cnt+=q->isword;//中途可能会出现0的地方
q->isword = -1;//设置为-1 标记已经访问完成
q = q->fail;//通过失败指针进行查找
}
indx++;
}
}
void freenode(Tree *p)
{
for(int i =0;i<26;i++)
if(p->next[i])
freenode(p->next[i]);
free(p);
}
int main()
{
int ncase;
scanf("%d",&ncase);
while(ncase--)
{
cnt =0;
root = (Tree *)malloc(sizeof(Tree));
root->isword =0;
root->fail = NULL;
memset(root->next,0,sizeof(root->next));
int m;
scanf("%d",&m);
while(m--)
{
scanf("%s",pattern);
Insert(pattern);
}
scanf("%s",text);
build_AC_automaton();
find_in_AC_automaton();
printf("%d\n",cnt);
freenode(root);//用完之后需要释放以防止内存不够
}
return 0;
}