ac自动机

ac自动机通常用来解决多字符串匹配问题,如从字符串s找字符串t[i](i<=n),如果直接用KMP那么时间复杂度为,而用ac自动机时间复杂度为

ac自动机可以认为是kmp和trie的结合,因为ac自动机就是在trie的基础上怎加了fail变量,fail指向的是当前字符串的最长后缀的尾节点,

作用就是在当前匹配失败时,将当前指针转向fail指向的位置,继续匹配,这样就避免了重复匹配,类似于kmp的next数组的作用。

下面是HDU 2222 Keywords Search模板代码,求得是出现在主串中的子串个数(重复出现算一次)。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<queue>
 5 #include<algorithm>
 6 using namespace std;
 7 const int N=1e6+5;
 8 const int M=5e5+5;
 9 
10 int idx;
11 int trie[M][26],fail[M],cnt[M];
12 char s[N];
13 
14 void init(){
15     idx=0;
16     memset(trie,-1,sizeof(trie));
17     memset(fail,0,sizeof(fail));
18     memset(cnt,0,sizeof(cnt));
19 }
20 
21 //插入模式串
22 void Insert(char *s){
23     int len=strlen(s);
24     int now=0;
25     for(int i=0;i<len;i++){
26         int ch=s[i]-'a';
27         if(trie[now][ch]==-1)
28             trie[now][ch]=++idx;
29         now=trie[now][ch];
30     }
31     cnt[now]++;
32 }
33 
34 //获得fail指针
35 void getfail(){
36     fail[0]=0;
37     queue<int>q;
38     for(int i=0;i<26;i++){
39         if(trie[0][i]==-1)
40             trie[0][i]=0;
41         else{
42             fail[trie[0][i]]=0;
43             q.push(trie[0][i]);
44         }
45     }
46     while(!q.empty()){
47         int u=q.front();
48         q.pop();
49         for(int i=0;i<26;i++){
50             if(trie[u][i]!=-1){
51                 fail[trie[u][i]]=trie[fail[u]][i];
52                 q.push(trie[u][i]);
53             }
54             else trie[u][i]=trie[fail[u]][i];
55         }
56     }
57 }
58 
59 //这里的意思是如果a出现在s中,那么作为a后缀的b肯定也在s中,所以不断找后缀
60 int get(int u){
61     int res=0;
62     while(u){
63         res+=cnt[u];
64         cnt[u]=0;
65         u=fail[u];
66     }
67     return res;
68 }
69 
70 //字符串匹配
71 int match(char *s){
72     int len=strlen(s),now=0,ans=0;
73     for(int i=0;i<len;i++){
74         int ch=s[i]-'a';
75         now=trie[now][ch];
76         //if(cnt[now])          注意这里不能判断cnt[now]>0,比如在she中找模式串she、h其中h是sh的的后缀而cnt[节点h]=0。
77         ans+=get(now);
78     }
79     return ans;
80 }
81 
82 int main(){
83     int t;
84     scanf("%d",&t);
85     while(t--){
86         init();
87         int n;
88         scanf("%d",&n);
89         for(int i=0;i<n;i++){
90             scanf("%s",s);
91             Insert(s);
92         }
93         scanf("%s",s);
94         getfail();
95         printf("%d
",match(s));
96     }
97     return 0;
98 }
原文地址:https://www.cnblogs.com/fu3638/p/8543968.html