题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2896
题意:给出n个模式串,再给出m个字符串,问这些字符串包含那些模式串
思路:ac自动机,先以模式串构建字典树,再以字典树构建fail标记,fail标记类似于KMP的next前缀数组,可以跳转到重复前缀的结尾,查询的时候利用fail标记就可以提高多模式串匹配的效率
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
struct Tree
{
Tree *Next[100];
Tree *fail;
int ed;
}*que[1000030];
Tree *tree;
int top=-1;
int stk[100030];
char str1[1030],str2[100030];
void Insert(char s[],int num)
{
int len=strlen(s);
Tree *p=tree;
for (int i=0;i<len;i++)
{
int tmp=s[i]-' ';
if (p->Next[tmp]==NULL)
{
Tree *newtree=new Tree;
for (int j=0;j<100;j++)
newtree->Next[j]=NULL;
newtree->fail=NULL;
newtree->ed=0;
p->Next[tmp]=newtree;
}
p=p->Next[tmp];
}
p->ed=num;
}
void acbuild()
{
int fr=0,re=-1;
que[++re]=tree;
while (fr<=re)
{
Tree *p=que[fr++];
Tree *tmp=NULL;
for (int i=0;i<100;i++)
{
Tree *q=p->Next[i];
if (p->Next[i]!=NULL)
{
if (p==tree)
q->fail=tree;
else
{
Tree *tmp=p->fail;
while (tmp!=NULL)
{
if (tmp->Next[i]!=NULL)
{
q->fail=tmp->Next[i];
break;
}
tmp=tmp->fail;
}
if (tmp==NULL) q->fail=tree;
}
que[++re]=p->Next[i];
}
}
}
}
int query(char s[])
{
Tree *p=tree;
int len=strlen(s),res=0;
for (int i=0;i<len;i++)
{
int tmp=s[i]-' ';//cout<<":"<<tmp<<endl;
while (p->Next[tmp]==NULL && p!=tree)
p=p->fail;
p=p->Next[tmp];
if (p==NULL)
p=tree;
else
{
Tree *q=p;
while (q!=tree)
{
if (q->ed!=0)
{
res+=1;
stk[top++]=q->ed;
}
q=q->fail;
}
}
}
return res;
}
int main()
{
int n,m;
while (scanf("%d",&n)!=EOF)
{
tree=new Tree;
for (int i=0;i<100;i++)
tree->Next[i]=NULL;
tree->fail=NULL;
for (int i=0;i<n;i++)
{
scanf("%s",&str1);
Insert(str1,i+1);
}//cout<<":"<<endl;;
acbuild();
scanf("%d",&m);
int res=0,tol=0;
for (int i=0;i<m;i++)
{
top=0;
scanf("%s",&str2);
res=query(str2);
if (res!=0)
{
sort(stk,stk+top);
printf("web %d:",i+1);
for (int i=0;i<top;i++)
printf(" %d",stk[i]);
printf("\n");
tol++;
}
}
printf("total: %d\n",tol);
}
}