本篇文章主要详细介绍$AC$自动机的$fail$指针:

如果有什么不完善的地方,请联系我$qwq$


前置知识:

1、建议学一下$kmp$算法

2、$Trie$


导入:

AC自动机是用来解决多模板匹配问题的,但是,如果就单纯的把每个模板串拼接在一起,或者单个单个匹配的话,肯定是会超时的,而它的思想是把所有的模式串建立一颗$Trie$,然后用文本串来匹配,那么我们就必须在这颗$Trie$树上进行快速跳转来优化,于是,AC自动机就诞生了


重点:fail指针到底是什么?

我们先来思考一个问题,假如我们按照上面的思想,把每一个模式串建立一颗字典树,那么怎样才能在这个模板串失配后快速跳到下一个有可能成功匹配的字符串来匹配呢?我们举个例子:假设文本串是$bcde$,模式串有两个,分别为$bce$和$cd$,我们为两个模式串建一颗$Trie$,如下图:

我们拿着文本串开始匹配,发现匹配到$2$节点后,就失配了,也就是模式串$bce$失配,那么我们如何快速跳到下一个模式串$cd$来匹配呢?这个时候你可能会说,到$0$节点开始匹配呀,可是这样其实就是重头匹配下一个字符串了,效率并不高,在这里,我们其实可以直接跳到$4$号节点开始匹配,为什么?那是因为我们发现$2$号节点是成功匹配了的,只是不能到$3$号节点去,但是我们发现$2$号节点匹配说明了字符$c$在文本串出现过,那么$c$必定会匹配,所以$0$到$4$节点是怎么样都会匹配的,多举些例子我们会发现,当某个模式串失配后,当另一个模式串的某个前缀等于失配模式串的后缀时,可以得到另一个模式串的前缀肯定会匹配,可以直接跳到前缀继续匹配,也就是下图:

所以,构建$fail$指针其实就是在找最长的与当前失配的模式串后缀相同的与下一个模式串的前缀,那么为什么要找相同的前后缀上面已经说了,就是因为要利用已知信息来加速匹配,那么为什么要最长呢?

其实最长的话就可以保证每个有可能匹配的模式串都匹配到,假设当前节点模式串失配了,就跳最大的前缀,如果又失配,就又到最大前缀的最大前缀,直到没有为止,这样就可以保证全部考虑到。


算法实现(强势图解$qwq$):

先插入代码供下面边模拟边理解

void s_insert(string ss,int order)//构建普通Trie
{
int now=0;
for(int i=0;i<ss.length();i++)
{
if(!ch[now][ss[i]-'a'])
ch[now][ss[i]-'a']=++cnt;
now=ch[now][ss[i]-'a'];
}
num[now]=order;
}
void s_build()//求fail指针
{
queue<int> dui;
for(int i=0;i<26;i++)
if(ch[0][i])
dui.push(ch[0][i]);
while(!dui.empty())
{
int now=dui.front();
dui.pop();
for(int i=0;i<26;i++)
if(ch[now][i])
{
fail[ch[now][i]]=ch[fail[now]][i];
dui.push(ch[now][i]);
}
else
ch[now][i]=ch[fail[now]][i];
}
}

  

下面的图片引用了某大佬的图片,

假设文本串为$ushersheishis$,模式串为$i$,$he$,$his$,$she$,$hers$,黄色结点表示当前的结点u,绿色结点表示已经$BFS$遍历完毕的结点,红/橙色的边表示$fail$指针。

$2$号节点的$fail$指针画错了,$fail[2]=0$.

我们重点分析结点$6$的$fail$指针构建:

  • 找到$6$的父节点$5$,$5$的$fail$指针指向$10$,然而$10$结点没有字母$'s'$连出的边;

  • 所以跳到$10$的$fail$指针指向的结点$0$,发现$0$结点有字母$'s'$连出的边,指向$7$结点;

  • 所以$fail[6]=7$.

另外,在构建$fail$指针的同时,我们也对$Trie$中模式串的结尾构建$fail$指针。这样在匹配到结尾后能自动跳转到下一个匹配项。具体见代码实现。


深入优化:

一般我们建立$AC$自动机都不会单纯的建立字典树,而是建立。。$emm$。。大概是。。字典图的样子吧

我们重点分析一下结点$5$遍历时的情况:

  • 显然,本来应该跳$2$次才能找到$7$号结点,但是我们通过$10$号结点的黑色边直接通过字母$s$找到了$7$号结点。

  • 因此,就能在$O(1)$的时间内对单个结点构造$fail$指针。

这就是$build$完成的两件事:构建$fail$指针和建立字典图。这个字典图也会在查询的时候起到关键作用。

匹配:


总结:

到此,你已经理解了整个$AC$自动机的内容。我们一句话总结$AC$自动机的运行原理: 构建字典图实现自动跳转,构建失配指针实现多模式匹配。

弱势图解AC自动机的更多相关文章

  1. 【集训第二天·翻水的老师】--ac自动机+splay树

    今天是第二天集训.(其实已经是第三天了,只是昨天并没有机会来写总结,现在补上) 上午大家心情都很愉快,因为老师讲了splay树和ac自动机. 但到了下午,我们的教练竟然跑出去耍了(excuse me? ...

  2. hdu 5955 Guessing the Dice Roll 【AC自动机+高斯消元】

    hdu 5955 Guessing the Dice Roll [AC自动机+高斯消元] 题意:给出 n≤10 个长为 L≤10 的串,每次丢一个骰子,先出现的串赢,问获胜概率. 题解:裸的AC自动机 ...

  3. AC自动机:Tire树+KMP

    简介 AC自动机是一个多模式匹配算法,在模式匹配领域被广泛应用,举一个经典的例子,违禁词查找并替换为***.AC自动机其实是Trie树和KMP 算法的结合,首先将多模式串建立一个Tire树,然后结合K ...

  4. 基于trie树做一个ac自动机

    基于trie树做一个ac自动机 #!/usr/bin/python # -*- coding: utf-8 -*- class Node: def __init__(self): self.value ...

  5. AC自动机-算法详解

    What's Aho-Corasick automaton? 一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一. 简单的说,KMP用来在一篇文章中匹配一个模式串:但 ...

  6. python爬虫学习(11) —— 也写个AC自动机

    0. 写在前面 本文记录了一个AC自动机的诞生! 之前看过有人用C++写过AC自动机,也有用C#写的,还有一个用nodejs写的.. C# 逆袭--自制日刷千题的AC自动机攻克HDU OJ HDU 自 ...

  7. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2545  Solved: 1419[Submit][Sta ...

  8. BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]

    3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 3198  Solved: 1532[Submit][Status ...

  9. BZOJ 1212: [HNOI2004]L语言 [AC自动机 DP]

    1212: [HNOI2004]L语言 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1367  Solved: 598[Submit][Status ...

随机推荐

  1. js图片压缩上传

    最近公司的移动产品相约app要做一次活动,涉及到图片上传,图片又不能太大,不然用户体验太差,必须先压缩再上传,所以用到了html5的canvas和FileReader,代码先上,小弟前端经验不足,代码 ...

  2. varnish HTTP头

    Cache-Control:指定了缓存如何处理内容.varnish关心max-age参数,并用它来计算对象的TTL.“Cache-Control:no-cache”是被忽略的.Age:varnish添 ...

  3. JAVA生成验证码代码

    生成base64格式图片验证码 /** * 验证码的候选内容 */ private char codeSequence[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', ...

  4. 数据库(mysql和oracle)

    1.   mysql索引:    https://www.jikewenku.com/22030.html 2.

  5. css鼠标悬浮控制元素隐藏与显示

    在网页开发中经常有需求是鼠标移动到一个元素A身上时,另外一个元素B显示. 如下图 当鼠标移到图片上时,相关的描述从下方显示出来. css实现原理与情景: A 是 B 的父元素 B 默认隐藏 B{opa ...

  6. 钉钉微应用内置浏览器js缓存清理

    html中引用的js文件加上版本号,如下: <script type="text/javascript" src="js/xxx.js?version=1.0.1& ...

  7. layer,备受青睐的web弹层组件

    //http://layer.layui.com/ 特别说明:事件需自己绑定,以下只展现调用代码. //初体验 layer.alert('内容') //第三方扩展皮肤 layer.alert('内容' ...

  8. iview表单验证数字

    验证输入字符串必须为数字 html: <FormItem label="兑换积分:" prop="exchangeIntegral"> <In ...

  9. git 操作实践

    git操作: - git是一个用于帮助用户实现版本控制的软件 #首先创建项目 1. cd到项目文件目录 2. 鼠标右键点击 Git Bash Here 3. git init #在项目文件目录生成 . ...

  10. sql 存储过程笔记3

    16:22 2014/1/26一.定义变量--简单赋值declare @a int set @a = 5 print @a --使用select语句赋值declare @user1 nvarchar( ...