HDU 2222 Keywords Search (AC自动机模板题)
题目链接:HDU 2222
终于看明白AC自动机了,自己敲的模板,1A。
首先在Trie树上”挂“上所有的单词。
然后在树上构造fail指针。
Trie树上每一个字母的fail指针要么指向父节点,要么指向root,如果其父节点上有相同的字母,指向父节点对应的字母,否则指向root;
可以看出需要一层一层的构建,所以需要用到队列BFS。
查询操作,如果顺着字典树找没有这个字母,就通过fail指针去找,直到找到或者找到root。
如果找到,并且字母为单词结尾,则cnt++,然后通过fail指针继续匹配看是否仍有可以匹配的单词。
源代码
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
struct node{
node *next[26];
int count ; //记录
node* fail;
node(){
count = 0;
fail = NULL;
memset(next,0,sizeof(next));
}
}*q[5000000];
int head,tail;
char str[1000010];
node *root;
void insert(char *s){ //构建trie
int len = strlen(s);
node *p = root;
for(int i=0;i<len;i++){
int index = s[i]-'a';
if(!p->next[index])
p->next[index] = new node;
p=p->next[index];
}
p->count++;
}
void build_ac_automation(){ //初始化fail指针
q[tail++] = root;
while(head<tail){
node *p = q[head++];
node *tmp = NULL;
for(int i=0;i<26;i++){
if(p->next[i] != NULL){
if(p == root)//首元素必须指根
p->next[i]->fail = root;
else{
tmp = p->fail; //失败指针(跳转指针)
while(tmp != NULL){
if(tmp->next[i] != NULL){//找到匹配
p->next[i]->fail = tmp->next[i];
break;
} //如果没找到,则继续向上一个失败指针找
tmp = tmp->fail;
}
if(tmp == NULL) //为空 则从头匹配
p->next[i]->fail = root;
}
q[tail++] = p->next[i];//下一层入队
}
}
}
}
int query(){
int len = strlen(str);
node *p = root;
int cnt = 0;
for(int i=0;i<len;i++){
int index = str[i]-'a';
while(p->next[index] == NULL && p!=root)
p = p->fail;
p = p->next[index];
if(p == NULL)
p = root;
node *tmp = p;//tmp 动 , p不动。
while(tmp != root && tmp->count != -1){
cnt += tmp->count;
tmp->count = -1;
tmp = tmp ->fail;
}
}
return cnt;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
head= tail = 0;
root = new node;
int n;
scanf("%d",&n);
char s[10010];
for(int i=0;i<n;i++){
scanf("%s",s);
insert(s);
}
build_ac_automation();
scanf("%s",str);
int ans = query();
printf("%d\n",ans);
}
return 0;
}

浙公网安备 33010602011771号