AC自动机 :
AC自动机算法分为3步:构造一棵Trie树,构造失败指针和模式匹配过程。
在学习 AC 自动机 之前 , 一般应先学会 字典树 (也就是 tire树 ) 和 KMP 算法 (fail指针的构造 就是这个思想)。
用模拟指针实现的AC自动机
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxn = 10000100;
struct Node {
int num, fail;
int next[26];
void init (){
for(int i = 0; i<=25 ; i++){
next[i] = 0;
}
fail = -1;
num = 0;
}
}node [maxn];
int n;
char s[1010][55];
int tot = 0 ;
void insert(char s[]){
int cur = 0;
for(int i=0;s[i];i++){
// cout << s[i]<<" ***";
int t = s[i] - 'A' ;
if(node[cur].next[t]){
cur = node[cur].next[t];
// cout << "cur:" <<cur <<endl;
}else{
node[cur].next[t] = ++tot;
node[tot].init();
cur = tot;
}
}
}
void get_fail (){
queue<int > Q;
Q.push(0);
while(!Q.empty()){
int now = Q.front();
Q.pop();
for(int i= 0;i<26;i++){
if(node[now].next[i]){
// cout <<"haha"<<endl;
int p = node[now].fail ;
int q = node[now].next[i];
while(p!=-1&& !node[p].next[i]){
p = node[p].fail;
}
if(p == -1 ) node[q].fail = 0;
else { node[q].fail = node[p].next[i];
// cout <<q<<"fail "<< node[q].fail<<endl;
}
Q.push(q);
}
}
}
}
void match (char s[]){
int len = strlen(s);
int rt = 0 ;
int p,ans;
for(int i=0 ;i < len ; i++){
// cout << s[i]<<"&&&& ";
int t = s[i]-'A';
if(t>25||t<0){
rt = 0 ;
continue;
}
p = rt ;
while(p!=-1&& !node[p].next[t]){
p = node[p].fail;
}
if(p==-1) rt = 0 ;
else rt = node[p].next[t];
node[rt].num ++ ;
// cout <<rt << "rt"<<endl;
}
}
int query(char s[]){
int p= 0 , rt= 0 ;
for(int i= 0 ;s[i];i++){
int t = s[i] - 'A';
if(node[p].next[t]){
p = node[p].next[t];
}else{
return 0 ;
}
}
return node[p].num;
}
char mode[2000100];
int main(){
while( ~scanf("%d",&n)){
for(int i=1;i<=n;i++){
scanf("%s",s[i]);
}
node[0].init();
tot = 0;
for(int i=1;i<=n ;i++){
insert(s[i]);
}
get_fail();
// cout <<"***"<<endl;
scanf("%s",mode);
match(mode);
// cout <<"**(()"<<endl;
for(int i=1;i<= n;i++){
// cout <<s[i]<<endl;
int ans = query(s[i]);
// cout << ans <<endl;
if(ans){
cout << s[i]<<": "<<ans<<endl;
}
}
}
return 0;
}