题目链接:HDU 3065
AC自动机第二题~
模板几乎没有改动,只是模式字符串中出现了字母以外的字符需要处理一下,还有需要将计数的标记取消。
源代码
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int kind = 27;
struct node{
node *next[kind];
int count ;
node* fail;
node(){
count = 0;
fail = NULL;
memset(next,0,sizeof(next));
}
}*q[5000000];
int ans[1111];
node *root;
int head,tail;
char word[1010][55];
char str[2000010];
void insert(char *s,int k){ //构建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 = k;
}
void build_ac_automation(){ //初始化fail指针
q[tail++] = root;
while(head<tail){
node *p = q[head++];
node *tmp = NULL;
for(int i=0;i<kind;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];//下一层入队
}
}
}
}
void query(){
int len = strlen(str);
node *p = root;
int cnt = 0;
int index;
for(int i=0;i<len;i++){
if(str[i]<'A' || str[i] > 'Z')
index = 26;
else
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 != 0){
ans[tmp->count]++;
tmp = tmp ->fail;
}
}
}
void clear(node *root){
if(!root)
return ;
else{
for(int i=0;i<kind;i++)
clear(root->next[i]);
}
delete(root);
}
int main(){
int n;
while(scanf("%d",&n)!=EOF){
memset(ans,0,sizeof(ans));
root = new node;
getchar();
for(int i=0;i<n;i++){
gets(word[i]);
insert(word[i],i+1);
}
gets(str);
head = tail = 0;
build_ac_automation();
query();
int m;
for(int i=1;i<=n;i++){
if(ans[i]){
printf("%s: %d\n",word[i-1],ans[i]);
}
}
clear(root);
}
return 0;
}