题目大意:给你一堆病毒串,再给你一些网站,问每个网站是否包含病毒串,若包括,包括哪几个病毒串,还有一共有几个网站包含病毒串。
啊啊,自己第一道AC自动机的题,还是比较简单的模板题吧,过几天要总结一下AC自动机呀。
思路很简单了,将所有病毒串构成trie树,然后求AC自动机,再用每个网站在AC自动机上跑就行了。跑的时候开一个数组记录每个网站包含的病毒串。每经过一个节点由失败指针向上移,看是否有病毒串(即flag为1的节点)。应该还可以优化的,不过数据量不大,跑的还是挺快的,呵呵。
过几天研究下AC自动机的数组实现,还有结合DP还有矩阵的题。到时候发个总结吧
挫代码如下:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define maxn 100100
#define knum 94
using namespace std;
struct trie
{
int flag;
trie *fail;
trie *go[knum];
}node[maxn],*root;
int tot;
trie * newnode()
{
memset(node[tot].go,NULL,sizeof(node[tot].go));
node[tot].fail=NULL;
node[tot].flag=0;
return &node[tot++];
}
queue <trie *> q;
char keyword[210];
char str[maxn];
void insert(char *str,int x)
{
trie *p=root;
int i,k,len=strlen(str);
for(i=0;i<len;i++)
{
k=str[i]-' ';
if(!p->go[k])
{
p->go[k]=newnode();
}
p=p->go[k];
}
p->flag=x;
}
void build_ac_automation()
{
int i;
root->fail=NULL;
q.push(root);
while(!q.empty())
{
trie *tmp=q.front();q.pop();
trie *p=NULL;
for(i=0;i<knum;i++)
{
if(tmp->go[i])
{
if(tmp==root)
tmp->go[i]->fail=root;
else
{
p=tmp->fail;
while(p)
{
if(p->go[i])
{
tmp->go[i]->fail=p->go[i];
break;
}
p=p->fail;
}
if(p==NULL)
tmp->go[i]->fail=root;
}
q.push(tmp->go[i]);
}
}
}
}
int vis[510];
int solve()
{
int i,len=strlen(str),tru=0;
trie *p=root;
for(i=0;i<len;i++)
{
int k=str[i]-' ';
while(p!=root&&p->go[k]==NULL)
p=p->fail;
p=p->go[k];
p=(p==NULL)?root:p;
trie *tmp=p;
while(tmp!=root)
{
if(tmp->flag)
{
vis[tmp->flag]=1,tru=1;
}
tmp=tmp->fail;
}
}
return tru;
}
int main()
{
int n,i;
while(scanf("%d",&n)!=EOF)
{tot=0;
root=newnode();
for(i=1;i<=n;i++)
{
scanf("%s",keyword);
insert(keyword,i);
}
build_ac_automation();
int qq,ans=0;
scanf("%d",&qq);
for(i=1;i<=qq;i++)
{
memset(vis,0,sizeof(vis));
scanf("%s",str);
if(solve())
{
printf("web %d:",i);
ans++;
for(int j=1;j<=n;j++)
if(vis[j])
printf(" %d",j);
printf("\n");
}
}
printf("total: %d\n",ans);
}
return 0;
}