【定义】

【自动机】  由 状态集 ,初始状态集 ,终止状态集 ,字母集 ,对应关系五个元素组成的结构

       可以简单的将状态集理解为结点初始状态集理解为初始点终止状态集理解为终点

字母集理解为一个状态能够拥有的出边的最大个数,而在自动机中,特殊的是,一个结点的所有出边必须都要存在

例如在AC自动机中,每个节点都必须要有26个字母的出边所指向的节点

对应关系,可以理解为连通的边,例:节点 u 的 ’a‘ 的出边能够到达节点 v ,这就是一组对应关系

注:自动机的概念不用知道也可以学自动机,但是个人感觉理解了自动机的含义,更容易去明白他的本质

而且后面学其他自动机也更容易理解

【模式串】  一个比较短的串,需要找  文本串上有多少个他

【文本串】   一个比较长的串,需要在  他上面有多少个模式串


【前置知识】

【trie树(字典树)】从根节点插入一个字符串,依次插入

【KMP】单文本 logn 复杂度内查找模式串出现次数

【强烈建议看最后的扩展】


【解决问题】

多个模式串匹配文本串

给定一个较长串为文本串,给定多个模式串,询问这两者的关系

(也有可能不只有一个文本串)

一般为出现次数什么的

AC自动机本身保存这个字符串的所有子串的相关信息

即这个子串作为模式串出现的次数,这个子串的后缀之中能够包含多少模式串


【算法思想】

这个自动机的优点和KMP类似,所以有的博客中也会说,这是一个树上KMP。

KMP的优点在于有next数组作为指针失配时的指针,使字符串匹配可以不需要再次查找已经查找的串

而AC自动机也有他的“next数组”,f a i l  

AC自动机中的 f a i l 指针表示的是,当当前匹配的模式串失效后,已经匹配的一半模式串的拥有最长后缀的模式串的结尾的位置

对于一个AC自动机,我们需要先把所有的模式串都插入一颗 trie 树

int trie[MAXN][26];
//s是需要插入的模式串
void insert(string s)
{int u = 0;//从根节点开始检索for (int i = 0; i < s.size(); i++){int x = s[i] - 'a';if (!trie[u][x])//如果没有这个节点//需要新开拓一个节点,保存这个新的分支
        {trie[u][x] = ++cnt;}u = trie[u][x];}val[u]++;//说明这个节点是一个模式串的结尾return;
}

然后根据我们对 f a i l 的定义去寻找f a i l 指针

void get_fail()
{queue<int> q;for (int i = 0; i < 26; i++)    if (trie[0][i])  fail[trie[0][i]] = 0, q.push(trie[0][i]);//让所有的根节点连接的节点的fail指针指向根节点//并且加入队列while (!q.empty()){int u = q.front(); q.pop();for (int i = 0; i < 26; i++)//循环查找每个字母    if (trie[u][i])//如果存在这个节点//
                        {//他的 fail 就是 他父节点的 fail 的这个字母的位置//因为等于是在后缀上新加了一个字母 fail[trie[u][i]] = trie[fail[u]][i];q.push(trie[u][i]);}elsetrie[u][i] = trie[fail[u]][i];//如果没有//向上递归一层,方便之后的查找
    }return;
}

这里应该有张图说明一下,但是我懒得画


【模板题】

【题目大意】给n个模式串和1个文本串,问有多少个模式串在文本串中出现过

【解决方法】在trie树上跑文本串

int query(string s)
{int u = 0, ans = 0;//从根节点开始依次查找for (int i = 0; i < s.size(); i++){u = trie[u][s[i] - 'a'];//走到自己这个位置字符所在的节点for (int t = u; t && ~val[t]; t = fail[t])//从这个节点开始向上跳fail指针//查找有没有符合要求的字符串,如果是则这个字符串就会被记录ans += val[t], val[t] = -1;//-1是为了防止被重复计算
    }return ans;
}

#include<cstdio>
#include<iostream>
#include<string>
#include<queue>
using namespace std;
const int MAXN = 1000010;
int fail[MAXN],cnt;
int trie[MAXN][26];
int val[MAXN];
void insert(string s)
{int u = 0;for (int i = 0; i < s.size(); i++){int x = s[i] - 'a';if (!trie[u][x]){trie[u][x] = ++cnt;}u = trie[u][x];}val[u]++;return;
}
void get_fail()
{queue<int> q;for (int i = 0; i < 26; i++)    if (trie[0][i])  fail[trie[0][i]] = 0, q.push(trie[0][i]);while (!q.empty()){int u = q.front(); q.pop();for (int i = 0; i < 26; i++)if (trie[u][i]){fail[trie[u][i]] = trie[fail[u]][i];q.push(trie[u][i]);}elsetrie[u][i] = trie[fail[u]][i];}return;
}
int query(string s)
{int u = 0, ans = 0;for (int i = 0; i < s.size(); i++){u = trie[u][s[i] - 'a'];for (int t = u; t && ~val[t]; t = fail[t])ans += val[t], val[t] = -1;}return ans;
}
int main()
{int T;cin >> T;while (T--){string s;cin >> s;insert(s);}get_fail();string s;cin >> s;printf("%d", query(s));return 0;
}

View Code


【扩展】

这一步扩展其实才是AC自动机的精髓所在,也是比赛中比较常用的方法

就像是网络流不可能直接给图找最大流,而是通过建图的方式考察对算法的理解

AC自动机也有同样的情况

那就是通过抽离 fail 指针,建 fail 树,并且对其进行一系列操作完成任务

这不就是AC自动机抽离fail指针建可持久化线段树么

讲解在另外一道题里面

【NOI 2011】 阿狸的打字机

转载于:https://www.cnblogs.com/rentu/p/11297951.html

算法学习:AC自动机相关推荐

  1. 算法导论—AC自动机

    华电北风吹 日期:2016-05-03 AC自动机是比较高效的多模式匹配算法.类似于KMP在模式串上的状态转移算法,AC自动机通过在trie树上建立状态转移,使得对匹配串遍历一遍就可以找到所有的模式串 ...

  2. KMP算法、AC自动机算法的原理介绍以及Python实现

    KMP算法 要弄懂AC自动机算法,首先弄清楚KMP算法. 这篇文章讲的很好: http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E ...

  3. 提高篇 第二部分 字符串算法 第4章 AC自动机

    https://blog.csdn.net/wangyh1008/article/details/81428056 [模板]AC自动机(加强版) 洛谷3796 AC自动机_A_loud_name-CS ...

  4. 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)

    图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...

  5. ac自动机 匹配最长前缀_AC自动机算法

    AC自动机简介: 首先简要介绍一下AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一.一个常见的例子就是给出n个单词,再给出一段包 ...

  6. AC自动机算法及模板

    AC自动机算法及模板 2016-05-08 18:58 226人阅读 评论(0) 收藏 举报  分类: AC自动机(1)  版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 关于 ...

  7. AC自动机 算法详解(图解)及模板

    要学AC自动机需要自备两个前置技能:KMP和trie树(其实个人感觉不会kmp也行,失配指针的概念并不难) 其中,KMP是用于一对一的字符串匹配,而trie虽然能用于多模式匹配,但是每次匹配失败都需要 ...

  8. AC自动机模板(【洛谷3808】)

    题面 题目背景 这是一道简单的AC自动机模版题. 用于检测正确性以及算法常数. 为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交. 题目描述 给定n个模式串和1个文本串,求有多少个模式串 ...

  9. 字符串处理【AC自动机】 - 原理 AC自动机详解

    字符串处理[AC自动机] - 原理 AC自动机详解 AC自动机(Aho-Corasick automaton)在1975年产生于贝尔实验室,是著名的多模匹配算法. 学习AC自动机,要有KMP和Trie ...

  10. Python实现多模匹配——AC自动机

    Python实现多模匹配--AC自动机 目标:学习AC自动机,多模匹配. 要求:尽可能用纯Python实现,提升代码的扩展性. 一.什么是AC自动机? AC自动机,Aho-Corasick autom ...

最新文章

  1. DevOps:怎么实现源代码注释和系统文档的自动化更新?
  2. 35岁不是程序员的坎儿,看不清楚这件事才是!
  3. golang map 判断key是否存在
  4. display属性_前端基础:Grid 布局教程,重新复习grid布局的容器和项目属性
  5. 2019年最值得关注的五大微服务发展趋势
  6. 算法笔记_100:蓝桥杯练习 算法提高 三个整数的排序(Java)
  7. 持有1000枚以上比特币的巨鲸地址数量有所下降
  8. php mail带附件,Pear Mail 发送邮件带附件_PHP教程
  9. mouseclick
  10. 搭建内网文件共享服务器,如何搭建共享服务器实现办公室文件共享?
  11. 英语发音规则---/ŋ/与/ŋg/的读音区别
  12. 计量经济学及Stata应用 陈强 第九章模型设定与数据问题习题9.3
  13. windows 7 远程桌面连接图文教程
  14. 全栈云服务是个什么东东?!
  15. win10 休眠设置无效_win10电脑休眠后无法唤醒的解决办法
  16. 嵌入式GEC6818利用多线程实现视频播放器
  17. 历经5年,一次业余网页游戏项目惨痛的失败经历
  18. php处理并发不如java_今天听人说 php 运算能力不比 java
  19. 关系数据库的查询处理
  20. 计算机二级成绩划分标准,计算机二级 成绩 等级是如何划分的

热门文章

  1. kafka模拟生产-消费者以及自定义分区
  2. 4.5/4.6 磁盘格式化 4.7/4.8 磁盘挂载 4.9 手动增加swap空间
  3. c++——结构与指针 类与指针
  4. 《信息可视化:交互设计(原书第2版)》——第2章基本概念
  5. vs转eclipse之工具快速上手篇
  6. 关于UIView的userInteractionEnabled属性
  7. iOS APP提交上架最新流程(转)
  8. 3D图形图像处理软件HOOPS介绍及下载
  9. 在linux下配置oracle的远程访问
  10. AWS推出深度学习容器,简化AI程序开发