复杂度:

查找O(n),维护O(n)

概要:

应用了kmp的自匹配思想,在trie建图时维护一个fali指针,指向上一个匹配的点,这点是用bfs做到。匹配串的时候同样没匹配到就和kmp一样返回。

应用:单串匹配多模板,维护多模板里边的信息。

技巧及注意:

插入和trie一样,然后是bfs。

在bfs的过程中,注意以根开头的不需要匹配fail,即ch[0][i]不需要匹配他们的fail,即为空。

然后在查找的时候当找到一个时我们要遍历这个节点的整个fail树,然后取出信息后记得将信息清空。

一定要注意!节点数是不超过n个串的总长度!!!一定要切记!!!

注意!!bfs的时候一定要维护信息!!!!

例题:

  1. 【BZOJ】1030: [JSOI2007]文本生成器(递推+ac自动机)(将自动机的节点作为转移的状态然后递推)
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <cmath>
  4. #include <string>
  5. #include <iostream>
  6. #include <algorithm>
  7. #include <queue>
  8. using namespace std;
  9. #define rep(i, n) for(int i=0; i<(n); ++i)
  10. #define for1(i,a,n) for(int i=(a);i<=(n);++i)
  11. #define for2(i,a,n) for(int i=(a);i<(n);++i)
  12. #define for3(i,a,n) for(int i=(a);i>=(n);--i)
  13. #define for4(i,a,n) for(int i=(a);i>(n);--i)
  14. #define CC(i,a) memset(i,a,sizeof(i))
  15. #define read(a) a=getint()
  16. #define print(a) printf("%d", a)
  17. #define dbg(x) cout << #x << " = " << x << endl
  18. #define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; }
  19. inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
  20. inline const int max(const int &a, const int &b) { return a>b?a:b; }
  21. inline const int min(const int &a, const int &b) { return a<b?a:b; }
  22.  
  23. using namespace std;
  24.  
  25. const int N=10000000, Type=26;
  26. int T[N][Type], w[N], fail[N], cnt, q[N], front, tail, ans;
  27. char str[1000000], st[1000000];
  28.  
  29. inline void ins(char s[]) {
  30. int len=strlen(s), now=0;
  31. rep(i, len) {
  32. int t=s[i]-'a';
  33. if(!T[now][t]) T[now][t]=++cnt;
  34. now=T[now][t];
  35. }
  36. ++w[now];
  37. }
  38. void bfs() {
  39. int now=0;
  40. q[tail++]=0;
  41. while(tail!=front) {
  42. now=q[front++]; if(front==N) front=0;
  43. rep(i, 26) if(T[now][i]) {
  44. q[tail++]=T[now][i]; if(tail==N) tail=0;
  45. if(now==0) continue;
  46. int p=fail[now];
  47. while(p && !T[p][i]) p=fail[p];
  48. fail[T[now][i]]=T[p][i];
  49. }
  50. }
  51. }
  52. void ac(char s[]) {
  53. int len=strlen(s), now=0;
  54. rep(i, len) {
  55. int t=s[i]-'a';
  56. while(now && !T[now][t]) now=fail[now];
  57. now=T[now][t];
  58. t=now;
  59. while(t) {
  60. ans+=w[t];
  61. w[t]=0;
  62. t=fail[t];
  63. }
  64. }
  65. }
  66. int main() {
  67. scanf("%s", str);
  68. int n=getint();
  69. while(n--) {
  70. scanf("%s", st);
  71. ins(st);
  72. }
  73. bfs();
  74. ac(str);
  75. print(ans);
  76. return 0;
  77. }

没错,就是AC自动机!(可惜不像金坷垃那样~)

不多说,放上模板,不难理解的。

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <queue>
  4. #define for1(i,a,n) for(i=a;i<=n;++i)
  5. #define for2(i,a,n) for(i=a;i<n;++i)
  6. #define for3(i,a,n) for(i=n;i>=a;--i)
  7. #define for4(i,a,n) for(i=n;i>a;--i)
  8. #define CC(i,a) memset(i, a, sizeof(i))
  9.  
  10. using namespace std;
  11.  
  12. const int N=10000000, Type=26;
  13. char a[N], b[N];
  14. int ch[N][Type], fail[N], w[N], ans, cnt=1;
  15. queue<int> q;
  16.  
  17. void ins(char* s) {
  18. int u=0, v, i, len=strlen(s);
  19. for2(i, 0, len) {
  20. v=s[i]-'a';
  21. if(!ch[u][v]) ch[u][v]=cnt++;
  22. u=ch[u][v];
  23. }
  24. w[u]++;
  25. }
  26.  
  27. void bfs() {
  28. fail[0]=0;
  29. q.push(0);
  30. int u, p, i;
  31. while(!q.empty()) {
  32. u=q.front(); q.pop();
  33. for2(i, 0, Type) if(ch[u][i]) {
  34. q.push(ch[u][i]); //先插入,后判断
  35. if(!u) continue; //不要在这里错了。。
  36. p=fail[u];
  37. while(p && !ch[p][i]) p=fail[p];
  38. fail[ch[u][i]]=ch[p][i];
  39. }
  40. }
  41. }
  42.  
  43. void ac(char* s) {
  44. int i, u=0, v, len=strlen(s), t;
  45. for2(i, 0, len) {
  46. v=s[i]-'a';
  47. while(u && !ch[u][v]) u=fail[u];
  48. u=ch[u][v];
  49. t=u;
  50. while(t) {
  51. ans+=w[t];
  52. w[t]=0;
  53. t=fail[t];
  54. }
  55. }
  56.  
  57. }
  58.  
  59. void init() {
  60. CC(fail, 0);
  61. CC(ch, 0);
  62. CC(w, 0);
  63. }
  64.  
  65. int main() {
  66. init();
  67. scanf("%s", a);
  68. int n, i;
  69. scanf("%d", &n);
  70. for1(i, 1, n) {
  71. scanf("%s", b);
  72. ins(b);
  73. }
  74. bfs();
  75. ac(a);
  76. printf("%d\n", ans);
  77.  
  78. return 0;
  79. }

注意一些细节即可

小结:ac自动机的更多相关文章

  1. AC自动机学习小结

    AC自动机 简要说明 \(AC\) 自动机,全称 \(Aho-Corasick\ automaton\) ,是一种有限状态自动机,应用于多模式串匹配.在 \(OI\) 中通常搭配 \(dp\) 食用. ...

  2. AC自动机详解 (P3808 模板)

    AC自动机笔记 0.0 前言 哇,好久之前就看了 KMP 和 Trie 树,但是似乎一直没看懂 AC自动机?? 今天灵光一闪,加上之前看到一些博客和视频,瞬间秒懂啊... 其实这个玩意还是蛮好理解的. ...

  3. AC自动机fail树小结

    建议大家学过AC自动机之后再来看这篇小结 fail树就是讲fail指针看做一条边连成的树形结构 fail指针在AC自动机中的含义是指以x为结尾的后缀在其他模式串中所能匹配的最长前缀的长度 所以在模式串 ...

  4. 【原创】AC自动机小结

    有了KMP和Trie的基础,就可以学习神奇的AC自动机了.AC自动机其实就是在Trie树上实现KMP,可以完成多模式串的匹配.           AC自动机 其实 就是创建了一个状态的转移图,思想很 ...

  5. AC自动机小结

    专题链接 第一题--hdu2222 Keywords Search ac自动机的模板题,入门题.  题解 第二题--hdu2896 病毒侵袭   一类病毒的入门题,类似模板  题解 第三题--hdu3 ...

  6. AC自动机算法小结

    AC自动机,可惜不能自动AC 转载:飘过的小牛 OIer55242 简介 Aho-Corasick automation 该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一.一个常见的例子就 ...

  7. 【专题】字符串专题小结(AC自动机 + 后缀自动机)

    AC自动机相关: $fail$树: $fail$树上以最长$border$关系形成父子关系,我们定一个节点对应的串为根到该节点的路径. 对于任意一个非根节点$x$,定$y = fa_{x}$,那$y$ ...

  8. AC自动机 & Fail树 专题练习

    Fail树就是AC自动机建出来的Fail指针构成的树. [bzoj3172][xsy1713]单词 题意 给定一些单词,求每个单词在所有单词里面的出现次数. 分析 构建Fail树,记录每个单词最后一个 ...

  9. Aho-Corasick automaton(AC自动机)解析及其在算法竞赛中的典型应用举例

    摘要: 本文主要讲述了AC自动机的基本思想和实现原理,如何构造AC自动机,着重讲解AC自动机在算法竞赛中的一些典型应用. 什么是AC自动机? 如何构造一个AC自动机? AC自动机在算法竞赛中的典型应用 ...

随机推荐

  1. Ubuntu上安装gtk2.0不能安装的问题,“下列的软件包有不能满足的依赖关系”

    zez@localhoss:~$ sudo apt-get install libgtk2.0-dev正在读取软件包列表... 完成正在分析软件包的依赖关系树       正在读取状态信息... 完成 ...

  2. PYTHON实现HTTP基本认证(BASIC AUTHENTICATION)

    参考: http://www.voidspace.org.uk/python/articles/authentication.shtml#id20 http://zh.wikipedia.org/wi ...

  3. XPath常用定位节点元素语句总结

    将一个XML或HTML文档转换成了DOM树结构后,如何才能定位到特定的节点?XPath实现了这样的功能,它通过DOM树中节点的路径和属性来导航,通过XPath路径表达式可以选择DOM树中的nodes( ...

  4. cocos2dx3.0rc导出自定义类到lua的方法

    以前要导出c++类到lua,就得手动维护pkg文件,那简直就是噩梦,3.0以后就会感觉生活很轻松了. 转载请注明出处http://www.cnblogs.com/mrblue/p/3637910.ht ...

  5. python 将pdf分页后插入至word中

    所用技术 1. python编程基础 2. 使用pyPdf 3. 使用python操作word 4. 正则表达式的使用 5. windows的bat编程 下面是一个pyPdf库使用的示例: from ...

  6. August 5th, 2016, Week 32nd, Friday

    Life is made up of small pleasures. 生活由各种细小的幸福构成. Don't expect too much. I am not qualified to get m ...

  7. 大端(big endian)和小端(little endian)

    http://www.cnblogs.com/Romi/archive/2012/01/10/2318551.html 当前的存储器,多以byte为访问的最小单元,当一个逻辑上的地址必须分割为物理上的 ...

  8. C++实现大数据乘法

    结构体定义与封装 struct bigdatacom { private : ]; ]; public : void init(const char *str1,const char *str2) { ...

  9. C++基础内容复习

    下列语句定义了5个变量: int count; double sales_price,sum; std::string title; Sales_item bookItem; 每个定义都是以类型说明符 ...

  10. ASP.NET MVC 3 使用Model自定义验证的样式

    1.修改jquery.validate.unobtrusive.js 将onError方法修改 //修改的部分 //////////////////////////////////////////// ...