虽然看明白了KMP和字典树,但是AC自动机还是没怎么理解QAQ...
附上讲解博客Orz:https://blog.csdn.net/qq_30346729/article/details/78835040
https://www.cnblogs.com/cjyyb/p/7196308.html
1.HDU2222 Keywords Search
kuangbin的模板,附上AC代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define ll long long
const int MAX=1000005;
int vis[MAX][26];
int fail[MAX];
int en[MAX];
int root,l;
int newnode()
{
for(int i=0;i<26;i++)
vis[l][i]=-1;
en[l++]=0;
return l-1;
}
void init()
{
l=0;
root=newnode();
}
void ins(char s[])
{
int len=strlen(s);
int now=root;
for(int i=0;i<len;i++)
{
int id=s[i]-'a';
if(vis[now][id]==-1)
vis[now][id]=newnode();
now=vis[now][id];
}
en[now]++;
}
void build()
{
queue<int>q;
fail[root]=root;
for(int i=0;i<26;i++)
{
if(vis[root][i]==-1)
vis[root][i]=root;
else
{
fail[vis[root][i]]=root;
q.push(vis[root][i]);
}
}
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(vis[now][i]==-1)
vis[now][i]=vis[fail[now]][i];
else
{
fail[vis[now][i]]=vis[fail[now]][i];
q.push(vis[now][i]);
}
}
}
}
int query(char s[])
{
int len=strlen(s);
int now=root;
int ans=0;
for(int i=0;i<len;i++)
{
int id=s[i]-'a';
now=vis[now][id];
int tmp=now;
while(tmp!=root)
{
ans+=en[tmp];
en[tmp]=0;
tmp=fail[tmp];
}
}
return ans;
}
int main()
{
char s[MAX];int n;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
init();//注意不能少!!
for(int i=0;i<n;i++)
{
scanf("%s",s);
ins(s);
}
build();
scanf("%s",s);
printf("%d\n",query(s));
}
return 0;
}
2.HDU2896病毒侵袭
这道题最大的坑点就在于没有规定全是小写字母。。。通过做这道题,对模板多了一点点点点理解,果然我还是太菜了啊55555...附上AC代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
#define ll long long
const int MAX=205*500;
int vis[MAX][128];//没有规定必须是小写字母,26不够,ASCII码值的范围:0-127
int fail[MAX];
int en[MAX];
int root,l;
int n;
int newnode()
{
for(int i=0;i<128;i++)
vis[l][i]=-1;
en[l++]=0;
return l-1;
}
void init()
{
l=0;
root=newnode();
}
void ins(char s[],int k)
{
int len=strlen(s);
int now=root;
for(int i=0;i<len;i++)
{
int id=s[i];//没有规定必须是小写字母,所以直接用s[i]的ASCII码值
if(vis[now][id]==-1)
vis[now][id]=newnode();
now=vis[now][id];
}
en[now]=k;//记录病毒的id
}
void build()
{
queue<int>q;
fail[root]=root;
for(int i=0;i<128;i++)
{
if(vis[root][i]==-1)
vis[root][i]=root;
else
{
fail[vis[root][i]]=root;
q.push(vis[root][i]);
}
}
while(!q.empty())
{
int now=q.front();
q.pop();
for(int i=0;i<128;i++)
{
if(vis[now][i]==-1)
vis[now][i]=vis[fail[now]][i];
else
{
fail[vis[now][i]]=vis[fail[now]][i];
q.push(vis[now][i]);
}
}
}
}
bool used[505];
int query(char s[],int k)
{
int len=strlen(s);
int now=root;
memset(used,false,sizeof(used));
bool sign=false;
for(int i=0;i<len;i++)
{
int id=s[i];
now=vis[now][id];
int tmp=now;
while(tmp!=root)
{
if(en[tmp])
{
sign=true;
used[en[tmp]]=true;
}
tmp=fail[tmp];
}
}
if(!sign)
return false;
else
{
printf("web %d:",k);
for(int i=1;i<=n;i++)
if(used[i])
printf(" %d",i);
printf("\n");
return true;//不要忘!
}
}
int main()
{
char s[10005];int m;
while(scanf("%d",&n)==1)
{
init();//注意不能少!!
for(int i=1;i<=n;i++)
{
scanf("%s",s);
ins(s,i);
}
build();
scanf("%d",&m);
int ans=0;
for(int i=1;i<=m;i++)
{
scanf("%s",s);
if(query(s,i))
ans++;
}
printf("total: %d\n",ans);
}
return 0;
}