要学AC自动机需要自备两个前置技能:KMP和trie树(其实个人感觉不会kmp也行,失配指针的概念并不难)
其中,KMP是用于一对一的字符串匹配,而trie虽然能用于多模式匹配,但是每次匹配失败都需要进行回溯,如果模式串很长的话会很浪费时间,所以AC自动机应运而生,如同Manacher一样,AC自动机利用某些操作阻止了模式串匹配阶段的回溯,将时间复杂度优化到了 O ( n ) O(n) O(n)(n)为文本串长度
转载注明出自bestsort.cn,谢谢合作
大家回复请去bestsort.cn回复吧,CSDN我每次都不知道你们回复的楼层在哪...点击查看评论它都不带自动跳转的QAQ
下面开始用图学习ac自动机吧(个人比较喜欢放图,能用一张图解决的绝不叨叨)
首先给定模式串"ash","shex","bcd","sha"
,然后我们根据模式串建立如下trie树:
然后我们再了解下一步:
ac自动机,就是在tire树的基础上,增加一个fail指针,如果当前点匹配失败,则将指针转移到fail指针指向的地方,这样就不用回溯,而可以路匹配下去了.(当前模式串后缀和fail指针指向的模式串部分前缀相同,如abce
和bcd
,我们找到c
发现下一个要找的不是e
,就跳到bcd
中的c
处,看看此处的下一个字符(d
)是不是应该找的那一个)
一般,fail指针的构建都是用bfs实现的
首先每个模式串的首字母肯定是指向根节点的(一个字母你瞎指什么指,指了也是头字母有什么用嘛)
现在第一层bfs遍历完了,开始第二层
(根节点为第0层)第二层a
的子节点为s
,但是我们还是要从a-z
遍历,如果不存在这个子节点我们就让他指向根节点(如下图红色的a
)
当我们遍历到s
的时候,由于存在s
这个节点,我们就让他的fail指针指向他父亲节点(a
)的fail指针指向的那个节点(根
)的具有相同字母的子节点(第一层的s
),也就是这样
按照相同规律构建第二层后,到了第三层的h
点,还是按照上面的规则,我们找到h
的父亲节点(s
)fail指针指向的那个位置(第一层的s
)然后指向它所指向的相同字母根->s->h
的这个链的h
节点,如下图
完全构造好后的树
然后匹配就很简单了,这里以ashe
为例
我们先用ash
匹配,到h
了发现:诶这里ash
是一个完整的模式串,好的ans++
,然后找下一个e
,可是ash
后面没字母了啊,我们就跳到h
fail指针指向的那个h
继续找,还是没有?再跳,结果当前的h
指向的是根节点,又从根节点找,然而还是没有找到e
,程序END
过程如下图
喜闻乐见模板系列
#include <queue>
#include <cstdlib>
#include <cmath>
#include