题目链接: hdu 2896
题目大意: 给出N个模式串,最后给出M个主串
问有主串出现过哪些模式串,最后输出哪些主串能匹配模式串
解题思路: AC自动机建立字典树的用w值标记第几个模式串
定义k值,匹配时若字典树中的某个结点不等于k且w不为0则记录该点
有多个主串需要匹配,所以不需要改变w的值,但可以判断k的值
若该失败指针的结点k值已经被匹配过则不需要再次匹配
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define MAX 10010
struct snode{
int w,fail,k;
int next[128];
}Tree[MAX*6];
int Index,listb[MAX*6],kk,ans[510];
char ch[MAX];
void Insert(int Star,int Tlen,int k) //建立字典树
{
int i,S=Star,child;
for(i=1;i<=Tlen;i++)
{
child=ch[i-1];
if(Tree[S].next[child]==-1)
{
if(i==Tlen)
Tree[Index].w=k;
Tree[S].next[child]=Index++;
}
else
{
if(i==Tlen)
Tree[Tree[S].next[child]].w=k;
}
S=Tree[S].next[child];
}
}
void Build_fail(int Star) //建立失败指针
{
int i,tempv,now_fail,e,s;
e=s=0;
listb[s++]=Star;
while(s!=e)
{
tempv=listb[e++];
for(i=0;i<128;i++)
{
if(Tree[tempv].next[i]!=-1)
{
now_fail=Tree[tempv].fail;
while(now_fail!=-1)
{
if(Tree[now_fail].next[i]!=-1)
{
Tree[Tree[tempv].next[i]].fail=Tree[now_fail].next[i];
break;
}
now_fail=Tree[now_fail].fail;
}
if(Tree[Tree[tempv].next[i]].fail==-1) //找不到失败指针,则指向根节点
Tree[Tree[tempv].next[i]].fail=0;
listb[s++]=Tree[tempv].next[i];
}
}
}
}
int Ac_auto(int k,int Tlen) //BFS匹配
{
int i,p=0,child,temp,sum=0;
for(i=1;i<=Tlen;i++)
{
child=ch[i-1];
while(Tree[p].next[child]==-1&&p!=0)
{
p=Tree[p].fail;
}
p=(Tree[p].next[child]==-1)?0:Tree[p].next[child]; //**
temp=p;
while(Tree[temp].w!=-1&&temp!=0&&Tree[temp].k!=k)
{
if(Tree[temp].w!=-1&&Tree[temp].k!=k) //匹配过则不需要再次匹配
{
ans[kk++]=Tree[temp].w;
sum++;
}
Tree[temp].k=k;
temp=Tree[temp].fail;
}
}
return sum;
}
int main()
{
int i,j,n,m,temp,sumn;
while(scanf("%d",&n)!=EOF)
{
getchar();
Index=1;
memset(Tree,-1,sizeof(Tree)); //初始化字典树
for(i=1;i<=n;i++)
{
gets(ch); //可能有空格输入
Insert(0,strlen(ch),i);
}
scanf("%d",&m);
getchar();
Build_fail(0);
for(i=1,sumn=0;i<=m;i++)
{
kk=0;
gets(ch); //可能有空格输入
temp=Ac_auto(i,strlen(ch)); //记录每个主串的匹配次数
if(temp>=1)
{
sumn++;
sort(ans,ans+kk); //从小到大输出匹配的模式串的序号
printf("web %d:",i);
for(j=0;j<kk;j++)
printf(" %d",ans[j]);
puts("");
}
}
if(sumn>=1)
printf("total: %d\n",sumn);
}
return 0;
}