HDU 2222 Keywords Search(AC自动机模板)
Keywords Search
入门题,是看b站的视频入门的,网址:http://www.bilibili.com/video/av6295004/index_2.html#page=2
【题目链接】Keywords Search
【题目类型】AC自动机
&题意:
给出n个串,然后给一篇文章,问这n个串有多少个在文章里面出现过。
trick:n个串可能有相同的,需按照不同串处理。
&代码:
无注释版
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define maxn 1000009
#define maxtot 500009
struct Aho {
struct state {
int next[26],cnt,fail;
} sNode[maxtot];
int size;
std::queue<int> que;
void Init() {
while(que.size()) que.pop();
for(int i=0; i<maxtot; i++) {
memset(sNode[i].next,0,sizeof(sNode[i].next));
sNode[i].fail=sNode[i].cnt=0;
}
size=1;
}
void Insert(char* S) {
int n=strlen(S),now=0;
for(int i=0; i<n; i++) {
char c=S[i];
if(!sNode[now].next[c-'a'])
sNode[now].next[c-'a']=size++;
now=sNode[now].next[c-'a'];
}
sNode[now].cnt++;
}
void Build() {
sNode[0].fail=-1;
que.push(0);
while(que.size()) {
int u=que.front(); que.pop();
for(int i=0; i<26; i++) if(sNode[u].next[i]) {
if(u==0) sNode[sNode[u].next[i]].fail=0;
else {
int v=sNode[u].fail;
while(v!=-1) {
if(sNode[v].next[i]) {
sNode[sNode[u].next[i]].fail=sNode[v].next[i];
break;
}
v=sNode[v].fail;
}
if(v==-1) sNode[sNode[u].next[i]].fail=0;
}
que.push(sNode[u].next[i]);
}
}
}
int Get(int u) {
int res=0;
while(u) {
res+=sNode[u].cnt;
sNode[u].cnt=0;
u=sNode[u].fail;
}
return res;
}
int March(char *S) {
int n=strlen(S);
int res=0,now=0;
for(int i=0; i<n; i++) {
char c=S[i];
if(sNode[now].next[c-'a'])
now=sNode[now].next[c-'a'];
else {
int v=sNode[now].fail;
while(v!=-1&&sNode[v].next[c-'a']==0) v=sNode[v].fail;
if(v==-1) now=0;
else now=sNode[v].next[c-'a'];
}
if(sNode[now].cnt) {
res+=Get(now);
}
}
return res;
}
} aho;
char S[maxn];
int main() {
// freopen("1.in","r",stdin),freopen("1.out","w",stdout);
int T;
scanf("%d",&T);
while(T--) {
int N;
aho.Init();
scanf("%d",&N);
for(int i=0; i<N; i++) {
scanf("%s",S);
aho.Insert(S);
}
aho.Build();
scanf("%s",S);
printf("%d\n",aho.March(S));
}
return 0;
}
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define MAX_N 1000009
#define MAX_Tot 500009
//AC自动机结构体
struct Aho {
//声明节点,注意节点内存在的信息
struct state {
int next[26];
int fail,cnt;
} stateTable[MAX_Tot];
//节点数量
int size;
//失配指针宽搜的队列
std::queue<int> que;
//初始化节点内容和size
void init() {
while(que.size()) que.pop();
for(int i=0; i<MAX_Tot; i++) {
memset(stateTable[i].next,0,sizeof(stateTable[i].next));
stateTable[i].fail=stateTable[i].cnt=0;
}
size=1;
}
//插入单词
void insert(char *S) {
int n=strlen(S);
//now代表现在处理到哪个节点了
int now=0;
for(int i=0; i<n; i++) {
char c=S[i];
//如果这个节点没有找到路,就新开一条路
if(!stateTable[now].next[c-'a'])
stateTable[now].next[c-'a']=size++;
//把现在的节点赋为将要走的节点
now=stateTable[now].next[c-'a'];
}
//遍历完后走到结束位置,个数++(因为本题有重复模式串的情况)
stateTable[now].cnt++;
}
//构造失配指针
void build() {
stateTable[0].fail=-1;
que.push(0);
while(que.size()) {
int u=que.front();
que.pop();
//BFS
for(int i=0; i<26; i++) {
if(stateTable[u].next[i]) {
//如果是根节点,那么他的fail指向0
if(u==0) stateTable[stateTable[u].next[i]].fail=0;
//否则就一直找到最长后缀,之后再赋值儿子的fail指针
else {
int v=stateTable[u].fail;
while(v!=-1) {
if(stateTable[v].next[i]) {
stateTable[stateTable[u].next[i]].fail=stateTable[v].next[i];
break;
}
v=stateTable[v].fail;
}
//如果v还是-1,那么fail就只能指向0了
if(v==-1) stateTable[stateTable[u].next[i]].fail=0;
}
//最后push进去,在for里的if里push
que.push(stateTable[u].next[i]);
}
}
}
}
int Get(int u) {
int res=0;
while(u) {
res=res+stateTable[u].cnt;
stateTable[u].cnt=0;
u=stateTable[u].fail;
}
return res;
}
int march(char *S) {
int n=strlen(S);
int res=0,now=0;
for(int i=0; i<n; i++) {
char c=S[i];
//如果这条路的next可以走就走这条
if(stateTable[now].next[c-'a'])
now=stateTable[now].next[c-'a'];
//否则就走fail指针的路
else {
int p=stateTable[now].fail;
while(p!=-1&&stateTable[p].next[c-'a']==0) p=stateTable[p].fail;
//如果始终没找到,就回到根节点
if(p==-1) now=0;
//如果找到了,就继续忘下走
else now=stateTable[p].next[c-'a'];
}
if(stateTable[now].cnt) {
res=res+Get(now);
}
}
return res;
}
} aho;
int T;
int N;
char S[MAX_N];
int main() {
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin),freopen("1.out","w",stdout);
#endif
scanf("%d",&T);
while(T--) {
aho.init();
scanf("%d",&N);
for(int i=0; i<N; i++) {
scanf("%s",S);
aho.insert(S);
}
aho.build();
scanf("%s",S);
printf("%d\n", aho.march(S));
}
return 0;
}