AC自己主动机

AC自己主动机是KMP和Trie的结合,主要处理多模板串匹配问题。以下推荐一个博客,有助于学习AC自己主动机。

这里另一个Kuangbin开的比赛,大家也能够做一下,加深对算法的理解。

以下是比赛中的题目,採用了notonlysuccess的模板。
HDU 2222 Keywords Search
题意:最裸的模板题,给定一些模板串以及一个文本串,要在文本串中找有多少个模板串。

  1. /*
  2. ID: wuqi9395@126.com
  3. PROG:
  4. LANG: C++
  5. */
  6. #include<map>
  7. #include<set>
  8. #include<queue>
  9. #include<stack>
  10. #include<cmath>
  11. #include<cstdio>
  12. #include<vector>
  13. #include<string>
  14. #include<fstream>
  15. #include<cstring>
  16. #include<ctype.h>
  17. #include<iostream>
  18. #include<algorithm>
  19. #define INF (1<<30)
  20. #define PI acos(-1.0)
  21. #define mem(a, b) memset(a, b, sizeof(a))
  22. #define rep(i, n) for (int i = 0; i < n; i++)
  23. #define debug puts("===============")
  24. typedef long long ll;
  25. using namespace std;
  26. const int maxnode = 500100;
  27. const int charset = 26;
  28. struct ACAutomaton {
  29. int ch[maxnode][charset];
  30. int fail[maxnode];
  31. int Q[maxnode];
  32. int val[maxnode];
  33. int sz;
  34. int ID[128];
  35.  
  36. //初始化,计算字母相应的儿子ID,如:'a'->0 ... 'z'->25
  37. void init() {
  38. fail[0] = 0;
  39. for (int i = 0; i < charset; i++) ID[i + 'a'] = i;
  40. }
  41. //又一次建树需先Reset
  42. void reset() {
  43. memset(ch[0], 0, sizeof(ch[0]));
  44. sz = 1;
  45. }
  46. //将权值为key的字符串a插入到trie中
  47. void Insert(char *s, int key) {
  48. int u = 0;
  49. for ( ; *s; s++) {
  50. int c = ID[*s];
  51. if (!ch[u][c]) {
  52. memset(ch[sz], 0, sizeof(ch[sz]));
  53. val[sz] = 0;
  54. ch[u][c] = sz++;
  55. }
  56. u = ch[u][c];
  57. }
  58. val[u] += key;
  59. }
  60. //建立AC自己主动机,确定每一个节点的权值以及状态转移
  61. void Construct () {
  62. int *s = Q, *e = Q;
  63. for (int i = 0; i < charset; i++) {
  64. if (ch[0][i]) {
  65. fail[ch[0][i]] = 0;
  66. *e ++ = ch[0][i];
  67. }
  68. }
  69. while(s != e) {
  70. int u = *s++;
  71. for (int i = 0; i < charset; i++) {
  72. int &v = ch[u][i];
  73. if (ch[u][i]) {
  74. *e ++ = v;
  75. fail[v] = ch[fail[u]][i];
  76. } else {
  77. v = ch[fail[u]][i];
  78. }
  79. }
  80. }
  81. }
  82. //最基础的查询,询问一个字符串中出现了多少模板串
  83. int query(char *s) {
  84. int ans = 0, u = 0;
  85. for ( ; *s; s++) {
  86. int c = ID[*s];
  87. u = ch[u][c];
  88. int tmp = u;
  89. while(tmp) {
  90. ans += val[tmp];
  91. val[tmp] = 0;
  92. tmp = fail[tmp];
  93. }
  94. }
  95. return ans;
  96. }
  97. }AC;
  98. char str[1000100];
  99. int main() {
  100. AC.init();
  101. int t, n;
  102. scanf("%d", &t);
  103. while(t--) {
  104. scanf("%d", &n);
  105. AC.reset();
  106. for (int i = 0; i < n; i++) {
  107. scanf("%s", str);
  108. AC.Insert(str, 1);
  109. }
  110. AC.Construct();
  111. scanf("%s", str);
  112. printf("%d\n", AC.query(str));
  113. }
  114. return 0;
  115. }

HDU 2896 病毒侵袭

题意:有N个病毒,M个文本串,问每一个文本串出现了多少个病毒,各自是哪些?一共同拥有多少个文本串出现了病毒?
思路:这道题的病毒能够包括全部可见ASC码值

  1. /*
  2. ID: wuqi9395@126.com
  3. PROG:
  4. LANG: C++
  5. */
  6. #include<map>
  7. #include<set>
  8. #include<queue>
  9. #include<stack>
  10. #include<cmath>
  11. #include<cstdio>
  12. #include<vector>
  13. #include<string>
  14. #include<fstream>
  15. #include<cstring>
  16. #include<ctype.h>
  17. #include<iostream>
  18. #include<algorithm>
  19. #define INF (1<<30)
  20. #define PI acos(-1.0)
  21. #define mem(a, b) memset(a, b, sizeof(a))
  22. #define rep(i, n) for (int i = 0; i < n; i++)
  23. #define debug puts("===============")
  24. typedef long long ll;
  25. using namespace std;
  26. const int maxnode = 100100;
  27. const int charset = 128;
  28. struct ACAutomaton {
  29. int ch[maxnode][charset];
  30. int fail[maxnode];
  31. int Q[maxnode];
  32. int val[maxnode];
  33. int sz;
  34. int ID[128];
  35. void init() {
  36. fail[0] = 0;
  37. for (int i = 0; i < charset; i++) ID[i] = i;
  38. }
  39. void reset() {
  40. sz = 1;
  41. memset(ch[0], 0, sizeof(ch[0]));
  42. }
  43. void Insert(char *s, int key) {
  44. int u = 0;
  45. for ( ; *s; s++) {
  46. int c = ID[*s];
  47. if (!ch[u][c]) {
  48. memset(ch[sz], 0, sizeof(ch[sz]));
  49. val[sz] = 0;
  50. ch[u][c] = sz++;
  51. }
  52. u = ch[u][c];
  53. }
  54. val[u] = key;
  55. }
  56. void Construct () {
  57. int *s = Q, *e = Q;
  58. for (int i = 0; i < charset; i++) {
  59. if (ch[0][i]) {
  60. *e++ = ch[0][i];
  61. fail[ch[0][i]] = 0;
  62. }
  63. }
  64. while(s != e) {
  65. int u = *s++;
  66. for (int i = 0; i < charset; i++) {
  67. int &v = ch[u][i];
  68. if (v) {
  69. *e++ = v;
  70. fail[v] = ch[fail[u]][i];
  71. } else {
  72. v = ch[fail[u]][i];
  73. }
  74. }
  75. }
  76. }
  77. void query(char *s, int &tot, int id) {
  78. int ans = 0, u = 0;
  79. set<int> S;
  80. set<int>::iterator it;
  81. S.clear();
  82. for (; *s; s++) {
  83. int c = ID[*s];
  84. u = ch[u][c];
  85. int tmp = u;
  86. while(tmp) {
  87. if (val[tmp]) S.insert(val[tmp]), ans++;
  88. tmp = fail[tmp];
  89. }
  90. }
  91. if (ans) {
  92. printf("web %d:", id);
  93. for (it = S.begin(); it != S.end(); it++) printf(" %d", *it);
  94. putchar('\n');
  95. tot++;
  96. }
  97. }
  98. }AC;
  99. char buf[210], str[10100];
  100. int main () {
  101. int n, m, tot = 0;
  102. scanf("%d", &n);
  103. AC.init();
  104. AC.reset();
  105. for (int i = 0; i < n; i++) {
  106. scanf("%s", buf);
  107. AC.Insert(buf, i + 1);
  108. }
  109. AC.Construct();
  110. scanf("%d", &m);
  111. for (int i = 0; i < m; i++) {
  112. scanf("%s", str);
  113. AC.query(str, tot, i + 1);
  114. }
  115. printf("total: %d\n", tot);
  116. return 0;
  117. }

HDU 3065 病毒侵袭持续中

题意:有N个病毒,一个文本串,问文本串中每一个病毒出现了多少次
思路:也是基础的模板,是多case。。

  1. /*
  2. ID: wuqi9395@126.com
  3. PROG:
  4. LANG: C++
  5. */
  6. #include<map>
  7. #include<set>
  8. #include<queue>
  9. #include<stack>
  10. #include<cmath>
  11. #include<cstdio>
  12. #include<vector>
  13. #include<string>
  14. #include<fstream>
  15. #include<cstring>
  16. #include<ctype.h>
  17. #include<iostream>
  18. #include<algorithm>
  19. #define INF (1<<30)
  20. #define PI acos(-1.0)
  21. #define mem(a, b) memset(a, b, sizeof(a))
  22. #define rep(i, n) for (int i = 0; i < n; i++)
  23. #define debug puts("===============")
  24. typedef long long ll;
  25. using namespace std;
  26. const int maxnode = 50010;
  27. const int charset = 128;
  28. int cnt[1100];
  29. struct ACAutomaton {
  30. int ch[maxnode][charset];
  31. int fail[maxnode];
  32. int Q[maxnode];
  33. int val[maxnode];
  34. int sz;
  35. int ID[128];
  36. void init() {
  37. fail[0] = 0;
  38. for (int i = 0; i < charset; i++) ID[i] = i;
  39. }
  40. void reset() {
  41. sz = 1;
  42. memset(ch[0], 0, sizeof(ch[0]));
  43. }
  44. void Insert(char *s, int key) {
  45. int u = 0;
  46. for ( ; *s; s++) {
  47. int c = ID[*s];
  48. if (!ch[u][c]) {
  49. memset(ch[sz], 0, sizeof(ch[sz]));
  50. val[sz] = 0;
  51. ch[u][c] = sz++;
  52. }
  53. u = ch[u][c];
  54. }
  55. val[u] = key;
  56. }
  57. void Construct () {
  58. int *s = Q, *e = Q;
  59. for (int i = 0; i < charset; i++) {
  60. if (ch[0][i]) {
  61. *e++ = ch[0][i];
  62. fail[ch[0][i]] = 0;
  63. }
  64. }
  65. while(s != e) {
  66. int u = *s++;
  67. for (int i = 0; i < charset; i++) {
  68. int &v = ch[u][i];
  69. if (v) {
  70. *e++ = v;
  71. fail[v] = ch[fail[u]][i];
  72. } else {
  73. v = ch[fail[u]][i];
  74. }
  75. }
  76. }
  77. }
  78. void query(char *s) {
  79. int u = 0;
  80. for (; *s; s++) {
  81. int c = ID[*s];
  82. u = ch[u][c];
  83. int tmp = u;
  84. while(tmp) {
  85. if (val[tmp]) cnt[val[tmp]]++;
  86. tmp = fail[tmp];
  87. }
  88. }
  89. }
  90. } AC;
  91. char buf[1100][55], str[2000100];
  92. int main () {
  93. int n, m, tot = 0;
  94. AC.init();
  95. while(~scanf("%d", &n)) {
  96. AC.reset();
  97. for (int i = 0; i < n; i++) {
  98. scanf("%s", buf[i]);
  99. AC.Insert(buf[i], i + 1);
  100. cnt[i + 1] = 0;
  101. }
  102. AC.Construct();
  103. scanf("%s", str);
  104. AC.query(str);
  105. for (int i = 1; i <= n; i++) if (cnt[i]) printf("%s: %d\n", buf[i - 1], cnt[i]);
  106. }
  107. return 0;
  108. }

ZOJ 3430 Detect the Virus

题意:有一种编码方式,将输进来的字符转化为二进制,然后6个为一组,不足补零,得到一个新的数字,每一个数字相应一个字符(见题面)。如今给你已经编码过的n个病毒,和m个编码过的文本串,问每一个文本串各包括多少种病毒。
思路:这里反编码的时候,会发现可能有256种状态,所以不能用字符串表示。反编码之后就是裸的AC自己主动机。
  1. /*
  2. ID: wuqi9395@126.com
  3. PROG:
  4. LANG: C++
  5. */
  6. #include<map>
  7. #include<set>
  8. #include<queue>
  9. #include<stack>
  10. #include<cmath>
  11. #include<cstdio>
  12. #include<vector>
  13. #include<string>
  14. #include<fstream>
  15. #include<cstring>
  16. #include<ctype.h>
  17. #include<iostream>
  18. #include<algorithm>
  19. #define INF (1<<30)
  20. #define PI acos(-1.0)
  21. #define mem(a, b) memset(a, b, sizeof(a))
  22. #define rep(i, n) for (int i = 0; i < n; i++)
  23. #define debug puts("===============")
  24. typedef long long ll;
  25. using namespace std;
  26. const int maxnode = 510 * 64;
  27. const int charset = 256;
  28. struct ACAutomaton {
  29. int ch[maxnode][charset];
  30. int fail[maxnode];
  31. int Q[maxnode];
  32. int val[maxnode];
  33. int sz;
  34. int ID[256];
  35. void init() {
  36. fail[0] = 0;
  37. //for (int i = 0; i < charset; i++) ID[i] = i;
  38. }
  39. void reset() {
  40. sz = 1;
  41. memset(ch[0], 0, sizeof(ch[0]));
  42. }
  43. void Insert(unsigned char s[], int key, int len) {
  44. int u = 0;
  45. for (int i = 0; i < len; i++) {
  46. int c = s[i];
  47. if (!ch[u][c]) {
  48. memset(ch[sz], 0, sizeof(ch[sz]));
  49. val[sz] = 0;
  50. ch[u][c] = sz++;
  51. }
  52. u = ch[u][c];
  53. }
  54. val[u] = key;
  55. }
  56. void Construct () {
  57. int *s = Q, *e = Q;
  58. for (int i = 0; i < charset; i++) {
  59. if (ch[0][i]) {
  60. *e++ = ch[0][i];
  61. fail[ch[0][i]] = 0;
  62. }
  63. }
  64. while(s != e) {
  65. int u = *s++;
  66. for (int i = 0; i < charset; i++) {
  67. int &v = ch[u][i];
  68. if (v) {
  69. *e++ = v;
  70. fail[v] = ch[fail[u]][i];
  71. } else {
  72. v = ch[fail[u]][i];
  73. }
  74. }
  75. }
  76. }
  77. void query(unsigned char s[], int len) {
  78. int u = 0, ans = 0;
  79. bool vis[520] = {0};
  80. for (int i = 0; i < len; i++) {
  81. int c = s[i];
  82. u = ch[u][c];
  83. int tmp = u;
  84. while(tmp) {
  85. if (val[tmp] && !vis[val[tmp]]) {
  86. ans++, vis[val[tmp]] = 1;
  87. }
  88. tmp = fail[tmp];
  89. }
  90. }
  91. printf("%d\n", ans);
  92. }
  93. } AC;
  94. char s[4000];
  95. unsigned char g[4000];
  96. unsigned char now[4000];
  97. void get(char *s, int len) {
  98. for (int i = 0; i < len; i++) {
  99. if (s[i] >= 'A' && s[i] <= 'Z') g[i] = s[i] - 'A';
  100. else if (s[i] >= 'a' && s[i] <= 'z') g[i] = s[i] - 'a' + 26;
  101. else if (s[i] >= '0' && s[i] <= '9') g[i] = s[i] - '0' + 52;
  102. else if (s[i] == '+') g[i] = 62;
  103. else g[i] = 63;
  104. }
  105. g[len] = 0;
  106. }
  107. int change(unsigned char g[], int len) {
  108. int cnt = 0;
  109. for (int i = 0; i < len; i += 4) {
  110. now[cnt++] = (g[i] << 2) | (g[i + 1] >> 4);
  111. if (i + 2 < len) now[cnt++] = (g[i + 1] << 4) | (g[i + 2] >> 2);
  112. if (i + 3 < len) now[cnt++] = (g[i + 2] << 6) | g[i + 3];
  113. }
  114. return cnt;
  115. }
  116. int main () {
  117. int n, m;
  118. AC.init();
  119. while(~scanf("%d", &n)) {
  120. AC.reset();
  121. for (int i = 0; i < n; i++) {
  122. scanf("%s", s);
  123. int len = strlen(s);
  124. while(s[len - 1] == '=') len--;
  125. get(s, len);
  126. int cnt = change(g, len);
  127. AC.Insert(now, i + 1, cnt);
  128. }
  129. AC.Construct();
  130. scanf("%d", &m);
  131. while(m--) {
  132. scanf("%s", s);
  133. int len = strlen(s);
  134. while(s[len - 1] == '=') len--;
  135. get(s, len);
  136. int cnt = change(g, len);
  137. AC.query(now, cnt);
  138. }
  139. putchar('\n');
  140. }
  141. return 0;
  142. }

POJ 2778 DNA Sequence

题意:DNA的序列由ACTG四个字母组成,如今给定m个不可行的序列。问随机构成的长度为n的序列中,有多少种序列是可行的(仅仅要包括一个不可行序列便不可行)。个数非常大,对100000取模。 

思路:AC自己主动机 + DP 解题报告

HDU 2243 考研路茫茫――单词情结
题意:给定一些词根,假设一个单词包括有词根,则觉得是有效的。如今问长度不超过L的单词里面,有多少有效的单词?

ZOJ 2619 Generator
题意:给定一个数N,代表能够选前N个字母。然后给定一个仅有前N个字母组成的字符串,问从空串開始构造,每次能够在已有基础上从前N个字母中挑选一个加在后面,问构造的字符串的长度期望是多少?



持续更新中


AC自己主动机的更多相关文章

  1. POJ 2778 DNA Sequence (AC自己主动机 + dp)

    DNA Sequence 题意:DNA的序列由ACTG四个字母组成,如今给定m个不可行的序列.问随机构成的长度为n的序列中.有多少种序列是可行的(仅仅要包括一个不可行序列便不可行).个数非常大.对10 ...

  2. hdu 2222 Keywords Search ac自己主动机

    点击打开链接题目链接 Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Ja ...

  3. 【UVA】1449-Dominating Patterns(AC自己主动机)

    AC自己主动机的模板题.须要注意的是,对于每一个字符串,须要利用map将它映射到一个结点上,这样才干按顺序输出结果. 14360841 1449 option=com_onlinejudge& ...

  4. POJ 3691 &amp; HDU 2457 DNA repair (AC自己主动机,DP)

    http://poj.org/problem?id=3691 http://acm.hdu.edu.cn/showproblem.php?pid=2457 DNA repair Time Limit: ...

  5. HDU 2896 病毒侵袭 AC自己主动机题解

    本题是在text里面查找key word的增强版.由于这里有多个text. 那么就不能够简单把Trie的叶子标志记录改动成-1进行加速了,能够使用其它技术.我直接使用个vis数组记录已经訪问过的节点, ...

  6. NYOJ 1085 数单词 (AC自己主动机模板题)

    数单词 时间限制:1000 ms  |  内存限制:65535 KB 难度:4 描写叙述 为了可以顺利通过英语四六级考试,如今大家每天早上都会早起读英语. LYH本来以为自己在6月份的考试中能够通过六 ...

  7. hdu 4057 AC自己主动机+状态压缩dp

    http://acm.hdu.edu.cn/showproblem.php?pid=4057 Problem Description Dr. X is a biologist, who likes r ...

  8. Keywords Search (ac 自己主动机)

    Keywords Search Problem Description In the modern time, Search engine came into the life of everybod ...

  9. HDU - 2825 Wireless Password(AC自己主动机+DP)

    Description Liyuan lives in a old apartment. One day, he suddenly found that there was a wireless ne ...

  10. Hdu 3341 Lost&#39;s revenge (ac+自己主动机dp+hash)

    标题效果: 举个很多种DNA弦,每个字符串值值至1.最后,一个长字符串.要安排你最后一次另一个字符串,使其没事子值和最大. IDEAS: 首先easy我们的想法是想搜索的!管她3721..直接一个字符 ...

随机推荐

  1. OCaml Language Sucks

    OCaml Language Sucks OCaml Language Sucks

  2. ABP中动态WebAPI原理解析

    ABP中动态WebAPI原理解析 动态WebAPI应该算是ABP中最Magic的功能之一了吧.开发人员无须定义继承自ApiController的类,只须重用Application Service中的类 ...

  3. wpf dll和exe合并成一个新的exe

    原文:wpf dll和exe合并成一个新的exe 微软有一个工具叫ILMerge可以合并dll exe等,但是对于wpf的应用程序而言这个工具就不好用了.我的这方法也是从国外一个博客上找来的.仅供大家 ...

  4. 再读TCP/IP网络7层协议

    随着工作的深入,每次读这7层协议,每次都有不同的理解. 分层名                                                               分层号   ...

  5. poj3206(bfs+最小生成树)

    传送门:Borg Maze 题意:有一个迷宫,里面有一些外星人,外星人用字母A表示,#表示墙,不能走,空格可以走,从S点出发,在起点S和A处可以分叉走,问找到所有的外星人的最短路径是多少? 分析:分别 ...

  6. hdu2612(bfs)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2612 题意:求2个点到任意一个KFC的距离之和,使其最小. 分析:由两个点出发分别两次bfs,求得到每 ...

  7. 你有PSD的学位吗? - dp的日志 - 网易博客

    你有PSD的学位吗? - dp的日志 - 网易博客 你有PSD的学位吗? 2011-08-01 12:58:40|  分类: 感悟 |  标签:自我提升   |字号 大中小 订阅       去年, ...

  8. HDOJ 2736 Surprising Strings

    Surprising Strings Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  9. 约瑟夫问题--list模拟循环链表

    约瑟夫问题 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描写叙述 n个人想玩残酷的死亡游戏,游戏规则例如以下: n个人进行编号,分别 ...

  10. SurfaceView的一个小应用:开发示波器

    SurfaceView与普通View还有一个重要区别:View的绘图必须在UI线程中进行,但SurfaceView不存在这个问题,因为它是由SurfaceHolder来完成的.所以对于View组件,如 ...