看毛片就能AC算法

KMP && ACA

KMP:

吼哇!

反正网上教程满天飞,我就不写了。

发个自己写的模板

 1  /**
 2     freopen("in.in", "r", stdin);
 3     freopen("right.out", "w", stdout);
 4 */
 5 //// /////////////////////////////
 6 #include <cstdio>
 7 #include <string>
 8 #include <iostream>
 9 using std::string;
10 const int N = 1000010;
11 
12 int nex[N];
13 
14 int main() {
15     freopen("in.in", "r", stdin);
16     freopen("right.out", "w", stdout);
17     string s, p;
18     std::cin >> s >> p;
19 
20     nex[0] = 0;
21     for(int i = 1, j = 0; i < p.size(); i++) {
22         while(j && p[i] != p[j]) {
23             j = nex[j - 1];
24         }
25         if(p[i] == p[j]) j++;
26 
27         /// while(j && p[i + 1] == p[j]) j = nex[j - 1];
28         /// 十分失败的优化,反例:
29         /// acccc
30         /// ccc
31         /// 001  :next
32         /// 可以看出能匹配两个串,但是这个优化只能算出一个来
33 
34         nex[i] = j;
35     }
36 
37     for(int i = 0, j = 0; i < s.size(); i++) {
38         while(j && s[i] != p[j]) {
39             j = nex[j - 1];
40         }
41         if(s[i] == p[j]) j++;
42         if(j == p.size()) {
43             printf("%d\n", i - j + 2);
44             j = nex[j - 1];
45         }
46     }
47 
48     for(int i = 0; i < p.size(); i++) {
49         printf("%d ", nex[i]);
50     }
51 
52     return 0;
53 }
KMP模板 洛谷P3375

 例题:

剪花布条

A + B for you again

Period

Milking Grid

业界大毒瘤动物园

AC自动机

就是KMP上trie,用以解决多串匹配问题。

当我花几天的时间理解KMP之后,AC自动机也就很显然了(这怎么就显然了?)

想当我学KMP满大街找教程,现在学AC自动机教程还没看完就懂了...所以说基础很重要。

大致想象一下就行了。直接发代码吧。

 1 #include <cstdio>
 2 #include <string>
 3 #include <iostream>
 4 #include <queue>
 5 #include <cstring>
 6 const int N = 1000010;
 7 
 8 using std::string;
 9 
10 struct AC {
11     int root, tot;
12     int tr[N][26], nex[N], ed[N];
13     bool vis[N];
14     AC() {
15         root = 1;
16         tot = 1;
17     }
18     void clear() {
19         for(int i = 1; i <= tot; i++) {
20             nex[i] = ed[i] = 0;
21             for(int j = 0; j < 26; j++) {
22                 tr[i][j] = 0;
23             }
24         }
25         return;
26     }
27 
28     inline void insert(string x) {
29         int p = root;
30         for(int i = 0; i < x.size(); i++) {
31             int f = x[i] - 'a';
32             if(!tr[p][f]) {
33                 tr[p][f] = ++tot;
34             }
35             p = tr[p][f];
36         }
37         ed[p]++;
38         return;
39     }
40     void getnex() {
41         nex[root] = root;
42         std::queue<int> Q;
43         Q.push(root);
44         while(!Q.empty()) {
45             int x = Q.front();
46             Q.pop();
47             for(int i = 0; i < 26; i++) {
48                 int y = tr[x][i];
49                 if(y) {
50                     int j = nex[x];
51                     while(j != root && !tr[j][i]) {
52                         j = nex[j];
53                     }
54                     if(tr[j][i] && x != root) {
55                         j = tr[j][i];
56                     }
57                     nex[y] = j;
58                     Q.push(y);
59                 }
60             }
61         }
62         return;
63     }
64     int solve(string x) {
65         int ans = 0;
66         memset(vis, 0, (tot + 1) * sizeof(bool));
67         for(int i = 0, j = root; i < x.size(); i++)  {
68             int f = x[i] - 'a';
69             while(j != root && !tr[j][f]) {
70                 j = nex[j];
71             }
72             if(tr[j][f])  {
73                 j = tr[j][f];
74             }
75             if(ed[j] && !vis[j]) {
76                 ans += ed[j];
77                 vis[j] = 1;
78             }
79         }
80         return ans;
81     }
82 }ac;
83 
84 int main() {
85     int n;
86     scanf("%d", &n);
87     string s;
88     for(int i = 1; i <= n; i++) {
89         std::cin >> s;
90         ac.insert(s);
91     }
92     ac.getnex();
93     std::cin >> s;
94     printf("%d", ac.solve(s));
95     return 0;
96 }
洛谷P3808
  1 #include <cstdio>
  2 #include <string>
  3 #include <iostream>
  4 #include <queue>
  5 #include <cstring>
  6 const int N = 1000010;
  7 
  8 using std::string;
  9 
 10 struct Ans {
 11     string s;
 12     int cnt;
 13 }a[N];
 14 
 15 struct AC {
 16     int root, tot;
 17     int tr[N][26], nex[N], ed[N];
 18     AC() {
 19         root = 1;
 20         tot = 1;
 21     }
 22     void clear() {
 23         for(int i = 1; i <= tot; i++) {
 24             nex[i] = ed[i] = 0;
 25             for(int j = 0; j < 26; j++) {
 26                 tr[i][j] = 0;
 27             }
 28         }
 29         tot = 1;
 30         return;
 31     }
 32 
 33     inline void insert(string x, int k) {
 34         int p = root;
 35         for(int i = 0; i < x.size(); i++) {
 36             int f = x[i] - 'a';
 37             if(!tr[p][f]) {
 38                 tr[p][f] = ++tot;
 39             }
 40             p = tr[p][f];
 41         }
 42         ed[p] = k;
 43         return;
 44     }
 45     void getnex() {
 46         nex[root] = root;
 47         std::queue<int> Q;
 48         Q.push(root);
 49         while(!Q.empty()) {
 50             int x = Q.front();
 51             Q.pop();
 52             for(int i = 0; i < 26; i++) {
 53                 int y = tr[x][i];
 54                 if(y) {
 55                     int j = nex[x];
 56                     while(j != root && !tr[j][i]) {
 57                         j = nex[j];
 58                     }
 59                     if(tr[j][i] && x != root) {
 60                         j = tr[j][i];
 61                     }
 62                     nex[y] = j;
 63                     Q.push(y);
 64                 }
 65             }
 66         }
 67         return;
 68     }
 69     void solve(string x) {
 70         for(int i = 0, j = root; i < x.size(); i++)  {
 71             int f = x[i] - 'a';
 72             while(j != root && !tr[j][f]) {
 73                 j = nex[j];
 74             }
 75             if(tr[j][f])  {
 76                 j = tr[j][f];
 77             }
 78             int jj = j;
 79             while(jj != root) {
 80                 if(ed[jj]) {
 81                     a[ed[jj]].cnt++;
 82                 }
 83                 jj = nex[jj];
 84             }
 85         }
 86         return;
 87     }
 88 }ac;
 89 
 90 int main() {
 91     int n;
 92     string x;
 93     while(scanf("%d", &n) && n) {
 94         ac.clear();
 95         for(int i = 1; i <= n; i++) {
 96             std::cin >> a[i].s;
 97             ac.insert(a[i].s, i);
 98         }
 99         ac.getnex();
100         std::cin >> x;
101         ac.solve(x);
102         int large = -1;
103         for(int i = 1; i <= n; i++) {
104             large = std::max(large, a[i].cnt);
105         }
106         printf("%d\n", large);
107         for(int i = 1; i <= n; i++) {
108             if(a[i].cnt == large) {
109                 std::cout << a[i].s << std::endl;
110             }
111         }
112         for(int i = 1; i <= n; i++) {
113             a[i].cnt = 0;
114         }
115     }
116     return 0;
117 }
洛谷P3796

重点在于getnex()函数。别的依题意稍作修改即可。

第二题有个优化:ed[nex[jj]]可能为0,会额外增加跳的次数。解决办法是搞一个g数组出来表示ed[]不为0的某个nex。

被之前失败的优化经历搞怕了,没用...

 

KMP与AC自动机的小差异:(在我的模板中)

KMP初始化的nex[0] = 0,而AC自动机的初始化nex[root]  =  root;

KMP中的nex[i]表示最长匹配数,是比下标多1的,而AC自动机中直接指向一个节点。

 

posted @ 2018-05-21 13:49  garage  阅读(...)  评论(...编辑  收藏