AC自动机相关Fail树和Trie图相关基础知识

2024-04-29 17:48

本文主要是介绍AC自动机相关Fail树和Trie图相关基础知识,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

装载自55242字符串AC自动机专栏

fail树

定义

把所有fail指针逆向,这样就得到了一棵树
(因为每个节点的出度都为1,所以逆向后每个节点入度为1,所以得到的是一棵树)

还账…

有了这个东西,我们可以做很多事…

对于AC自动机的构造前面的文章已经讲了,而在查询的时候,有一点感觉没有说清楚:对于x串在y串中出现,必然是在y串某个前缀的后缀与x串相同
fail指针指向与该节点表示串后缀相等的且长度最大的串(或前缀)的节点
然后,根据fail指针的原理,在查询的时候,沿着当前节点的fail指针向上查找,直到root结束。
这个过程就是在遍历当前构成的字符串的后缀中是否有其他的单词。

作用

那有了fail树这个东西,我们可以干什么呢?
考虑这样一个问题:
给定n个串,m个询问,每个询问为一对(x,y),询问串y包含几个串x;
n,m106 ,串的总长度 106
解法1:

建好AC自动机,然后在线去查询,查询的时候每碰到一个字符就顺着fail指针往前查找到root。

解法2:

离线查询,每次查询y对应的多个x,这个只要往前找的时候统计多个就好

可是,这些解法都会TLE…所以要利用fail树

fail树就是把fail指针反转后重新建的树,这样查询(x,y),y会出现在x的子树中先研究下查询对(x,y),如果串x出现在串y中,那么串y有几个前缀的后缀
以串x结尾,便是出现的次数,简单地说串y从某个位置顺着fail指针能到
达串x尾就增加一次.这是多对一的关系;换个角度想,如果是一对多的话会容易解决些,从串x的末尾逆着刚刚
从串y来的fail指针能到达几个y中位置,那么就有几次.上面那步很容易转换,但关键问题是如果逆着刚刚从串y来的指针走呢?
逆着fail指针重新建树!
这就是fail树了.当我们构建好了fail树之后,要做的就是查询x的子树中有几个节点属于串y.
求出fail树的dfs序,令l[x]和r[x]分别为x遍历开始和结束的位置.接着我们进行区间查询,令表示查询l[x]和r[x]之间有几个属于y的结点.把串y在ac自动机上的结点对应的下标全赋值成1,问题就转变为l[x]和r[x]里有几个1了,
这时使用树状数组来计算区间和.
我们采用离线查询,把所有有y的查询存起来,当遇到y的末节点的时候拿出来统一处理.
我们顺着建AC自动机时的路线再遍历一遍AC自动机,遇到普通字母对应下标的值赋成1,
遇到B减1,遇到P查询(NOI 2011 阿狸的打字机)

题目

  1. CF 163 E
  2. BZOJ 3172: [Tjoi2013]单词
  3. BZOJ 2434 [Noi2011]阿狸的打字机

TRIE图


建议先看一下 Trie图的构建、活用与改进
看不懂很正常….

定(xian)义(che)

Trie图实际上一个确定性有限状态自动机,比AC自动机增加了确定性这个属性.
对于AC自动机来说,当碰到一个不匹配的节点后可能要进行好几次回溯才能进行下一次匹配;但是对于trie图来说,可以每一步进行一次匹配,每碰到一个输入字符都有一个确定的状态节点。
trie图的后缀节点跟ac自动机的后缀指针基本一致,区别在于trie图的根添加了了所有字符集的边;另外trie图还会为每个节点补上所有字符集中的字符的边,而这个补边的过程实际上也是一个求节点的后缀节点的过程.不过这些节点都是虚的,我们不把它们加到图中,而是找到它们的等价节点即它们的后缀节点, 从而让这些边指向后缀节点就可以了.

实现

Trie图主要利用两个概念实现这种目的。 后缀节点 和 补边 操作.

相关操作

  1. 后缀节点,也就是每个节点的路径字符串去掉第一个字符后的字符串对应的 节点.计算这个节点的方法,是通过它父亲节点的后缀节点,很明显它父亲的 后缀节点与它的后缀节点的区别就是还少一个尾字符,设为c,所以节点的父 节点的指针的c孩子就是该节点的后缀节点.但是因为有时候它父亲不一定有c孩子,所以还得找一个与父亲的c孩子等价的节点.于是就碰到一个寻找等价 节点的问题。
  2. 而Trie图还有一个补边的操作,不存在的那个字符对应的边指向的节点实际 上可以看成一个虚节点,我们要找一个现有的并且与它等价的节点,将这个边 指向它.这样也实际上是要寻找等价节点。

实现相关

我们看怎么找到一个节点的等价节点,我们所谓的等价是指它们的危险性一致。那我们再看一个节点是危险节点的充要条件是:它的路径字符串本身就是一个危险单词,或者它的路径字符串的后缀对应的节点是一个危险节点.因此我们可以看到,如果这个节点对应的路径字符串本身不是一个危险单词.那它就与它的后缀节点是等价的.所以我们补边的时候,实际指向的是节点的后缀节点就可以了.

trie图实际上对trie树进行了改进,添加了额外的信息。
使得可以利用它方便的解决多模式串的匹配问题.跟kmp的思想一样,trie图也是希望利用现在已经匹配的信息,对未来的匹配提出指导.提出了一些新的概念。定义trie树上,从根到某个节点的路径上所有边上的字符连起来形成的字符串称为这个节点的路径字符串.如果某个节点的路径字符串以一个危险字符串结尾,那么这个节点就是危险节点:也就是说如果到达这个点代表是匹配的状态;否则就是安全节点。 那么如何判断某个节点是否危险呢?

根节点显然是安全节点。一个节点是危险节点的充要条件是:它的路径字符串本身就是一个危险单词,或者它的路径字符串的后缀(这里特指一个字符串去掉第一个字符后剩余的部分)对应的节点(一个字符串对应的节点,是指从trie图中的根节点开始,依次沿某个字符指定的边到达的节点)是一个危险节点。

那么如何求每一个节点的后缀节点呢?这里就可以里利用以前的计算信息,得到了。具体来说就是利用父亲节点的后缀节点,我们只要记住当前节点的最后一个字符设为C,那么父亲节点的后缀节点的C分支节点就是要求的后缀节点了。首先我们限定,根节点的后缀节点是根本身,第一层节点的后缀节点是根节点。这样我们可以逐层求出所有节点的后缀节点。但是这个过程中,可能出现一个问题:父亲节点的后缀节点可能没有c分支。这时候该怎么办呢?

如下图所示如果设当前节点的父亲节点的后缀节点为w,我们假设w具有c孩子为,我们可以看到对于w的整个c子树来说,因为根本不存在通向它们的边c,它们也就不可能是不良字符串,这样这些节点的危险性也就等价与它们的后缀节点的危险性了,而它们的后缀节点,实际上就是w的后缀节点的c孩子,如此回溯下去,最后就能找到。

总结

Trie图所起到的作用就是建立一个确定性有限自动机DFA,图中的每点都是一个状态,状态之间的转换用有向边来表示。Trie图是在Tire的基础上补边过来的,其实他应该算是AC自动机的衍生,AC自动机只保存其后缀节点,在使用时再利用后缀节点进行跳转,并一直迭代到找到相应的状态转移为止,这个应该算是KMP的思想。

过程:

1. 构建Trie,并保证根节点一定有|∑|个儿子。
2. 层次遍历Trie,计算后缀节点,节点标记,没有|∑|个儿子的对其进行补边。

后缀节点的计算:

1. 根结点的后缀节点是它本身。
2. 处于Trie树第二层的节点的后缀结点也是根结点。
3. 其余节点的后缀节点,是其父节点的后缀节点中有相应状态转移的节点(这里类似AC自动机的迭代过程)。

节点标记:

1.本身就有标记。
2.其后缀节点有标记。

补边:

用其后缀节点相应的状态转移来填补当前节点的空白。
最后Trie图中任意一个节点均有相应的状态转移,我们就用这个状态转移做动态规划。

这篇关于AC自动机相关Fail树和Trie图相关基础知识的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/946748

相关文章

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

计组基础知识

操作系统的特征 并发共享虚拟异步 操作系统的功能 1、资源分配,资源回收硬件资源 CPU、内存、硬盘、I/O设备。2、为应⽤程序提供服务操作系统将硬件资源的操作封装起来,提供相对统⼀的接⼝(系统调⽤)供开发者调⽤。3、管理应⽤程序即控制进程的⽣命周期:进程开始时的环境配置和资源分配、进程结束后的资源回收、进程调度等。4、操作系统内核的功能(1)进程调度能⼒: 管理进程、线

sqlite3 相关知识

WAL 模式 VS 回滚模式 特性WAL 模式回滚模式(Rollback Journal)定义使用写前日志来记录变更。使用回滚日志来记录事务的所有修改。特点更高的并发性和性能;支持多读者和单写者。支持安全的事务回滚,但并发性较低。性能写入性能更好,尤其是读多写少的场景。写操作会造成较大的性能开销,尤其是在事务开始时。写入流程数据首先写入 WAL 文件,然后才从 WAL 刷新到主数据库。数据在开始

hdu 3065 AC自动机 匹配串编号以及出现次数

题意: 仍旧是天朝语题。 Input 第一行,一个整数N(1<=N<=1000),表示病毒特征码的个数。 接下来N行,每行表示一个病毒特征码,特征码字符串长度在1—50之间,并且只包含“英文大写字符”。任意两个病毒特征码,不会完全相同。 在这之后一行,表示“万恶之源”网站源码,源码字符串长度在2000000之内。字符串中字符都是ASCII码可见字符(不包括回车)。

POJ 1625 自动机

给出包含n个可见字符的字符集,以下所提字符串均由该字符集中的字符构成。给出p个长度不超过10的字符串,求长为m且不包含上述p个字符串的字符串有多少个。 g++提交 int mat[108][108] ;int matn ;int N ;map<char ,int> to ;//ACconst int maxm = 108 ;const int kin

zoj 3228 ac自动机

给出一个字符串和若干个单词,问这些单词在字符串里面出现了多少次。单词前面为0表示这个单词可重叠出现,1为不可重叠出现。 Sample Input ab 2 0 ab 1 ab abababac 2 0 aba 1 aba abcdefghijklmnopqrstuvwxyz 3 0 abc 1 def 1 jmn Sample Output Case 1 1 1 Case 2

D4代码AC集

贪心问题解决的步骤: (局部贪心能导致全局贪心)    1.确定贪心策略    2.验证贪心策略是否正确 排队接水 #include<bits/stdc++.h>using namespace std;int main(){int w,n,a[32000];cin>>w>>n;for(int i=1;i<=n;i++){cin>>a[i];}sort(a+1,a+n+1);int i=1

两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容

1.访问位与修改位的题型(淘汰哪一页) 访问位:为1时表示在内存期间被访问过,为0时表示未被访问;修改位:为1时表示该页面自从被装入内存后被修改过,为0时表示未修改过。 置换页面时,最先置换访问位和修改位为00的,其次是01(没被访问但被修改过)的,之后是10(被访问了但没被修改过),最后是11。 2.内聚的类型 功能内聚:完成一个单一功能,各个部分协同工作,缺一不可。 顺序内聚:

go基础知识归纳总结

无缓冲的 channel 和有缓冲的 channel 的区别? 在 Go 语言中,channel 是用来在 goroutines 之间传递数据的主要机制。它们有两种类型:无缓冲的 channel 和有缓冲的 channel。 无缓冲的 channel 行为:无缓冲的 channel 是一种同步的通信方式,发送和接收必须同时发生。如果一个 goroutine 试图通过无缓冲 channel

log4j2相关配置说明以及${sys:catalina.home}应用

${sys:catalina.home} 等价于 System.getProperty("catalina.home") 就是Tomcat的根目录:  C:\apache-tomcat-7.0.77 <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" /> 2017-08-10