题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2222
题目大意:
给出多个单词,一篇文章,问给出的单词在文章中出现的次数。
AC自动机模板题,注意单词可能有重复
AC自动机详解:http://blog.csdn.net/niushuai666/article/details/7002823
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
struct node {
node *fail;
node *next[26];
int count;
node(){
fail=NULL;
count=0;
for(int i=0;i<26;++i){
next[i]=NULL;
}
}
};
node *root;
queue<node*> q;
char txt[1000010],key[100];
void insert(char *str){
int k,len;
int i;
node *p=root;
len=strlen(str);
for(i=0;i<len;++i){
k=str[i]-'a';
if(p->next[k]==NULL)
p->next[k]=new node();
p=p->next[k];
}
p->count++;
}
void build_ac(){ //初始化fail指针,BFS
node *now,*nex;
int i,j;
while(!q.empty())q.pop();
q.push(root);
while(!q.empty()){
now=q.front();
q.pop();
nex=NULL;
for(i=0;i<26;++i){
if(now->next[i]!=NULL){
if(now==root){ //第一个元素fail必指向根
now->next[i]->fail=root;
}else{
nex=now->fail; //失败指针
while(nex!=NULL){ //2种情况结束:匹配为空or找到匹配
if(nex->next[i]!=NULL){ //找到匹配
now->next[i]->fail=nex->next[i];
break;
}
nex=nex->fail;
}
if(nex==NULL) //为空则从头匹配
now->next[i]->fail=root;
}
q.push(now->next[i]);
}
}
}
}
int query(){
int k,len,res;
node *p=root;
res=0;
len=strlen(txt);
for(int i=0;i<len;++i){
k=txt[i]-'a';
while(p->next[k]==NULL&&p!=root) //跳转失败指针
p=p->fail;
p=p->next[k];
if(p==NULL)
p=root;
node *temp=p; //p不动,temp计算后缀串
while(temp!=root&&temp->count!=-1){
res+=temp->count;
temp->count=-1;//重复不再计算
temp=temp->fail;
}
}
return res;
}
int main(){
int t,n;
int i;
scanf("%d",&t);
while(t--){
root=new node();
scanf("%d",&n);
for(i=0;i<n;++i){
scanf("%s",key);
insert(key);
}
build_ac();
scanf("%s",txt);
printf("%d\n",query());
}
return 0;
}