自动机

洛谷2444:病毒

☆樱花仙子☆ 提交于 2020-01-25 22:59:18
洛谷2444:病毒 题意: 有n个二进制字符串,称为病毒。 构造一个二进制字符串,使得没有任何一个病毒出现在这个构造的二进制字符串中。 回答是否可以构造这样一个字符串。 思路: AC自动机。 AC自动机是一个多模式匹配的数据结构。 我们首先构造 \(trie\) 树并构建 \(fail\) 指针。 这时候 \(trie\) 树就不再是 \(trie\) 树了,经过加了几个 \(fail\) 指针变成了一张有向图。 如果存在这样一个无限的字符串,使得没有任何一个病毒是他的子串,那么会有什么情况呢? 拿这个字符串到自动机上匹配,无论怎么样也到不了某个病毒串的结尾位置,因为构造的字符串无限长,所以他会在自动机里无限地转圈圈。 所以问题转化为: 在AC自动机上找一个环,这个环上没有节点是病毒串的结尾。 注意一个节点的 \(fail\) 节点如果是结尾节点,那么他自身也应该是一个结尾节点。 画个图看看 #include<bits/stdc++.h> using namespace std; const int maxn = 3e4 + 10; char s[maxn]; int n; struct AC_Automaton { int trie[maxn][5]; int val[maxn]; int fail[maxn]; int tot; void ins(char *str) {

编译原理(语法分析)

删除回忆录丶 提交于 2020-01-25 13:14:11
文章目录 上下文无关文法 下推自动机PDA 自上而下语法分析 二义性 消除左递归 提取公共左因子 预测分析程序 自下而上语法分析 LR(0) 活前缀 项目 SLR(1) 如何判断一个文法是不是SLR(1)? 上下文无关文法 与正规式属于同一层面,表达语法分析的基本单元 越接近根节点的运算优先级越低 运算符左结合和右结合的判断: S=A+S 则+是右结合 A=A*id 则*是左结合 CSL上下文有关文法,sensitive CFL上下文无关文法,free 下推自动机PDA 相比NA自动机,多了下推栈和下推栈内字母表 给定语言,如何写出他的下推自动机? 例如L={a n cb n ,n>=0} 写出他对应的文法,S→aSb | c 生成相应的PDA M 这4个映射关系的含义 1,2,3的映射代表了栈顶是a,读头指向了a,用空串替换了栈里的a 4的映射代表了读头指向了S,栈中没有与之匹配的,故用空串表示,然后向栈里压入S的文法表达,aSb或者c PDA的推导过程,首先收到语言aacbb,栈内是S,表头指向a,因此用aSb替换掉栈内的S,此时栈顶变为a,a对a,抵消,以此类推,如果能抵消掉整个字符串,即最后#对#,代表这个语言符合语法,与定义的文法保持一致; 自上而下语法分析 自上而下分析的含义 从符号开始 从左到右 推导出最后的句子, 自上而下 建立它的分析树

浅谈序列自动机

二次信任 提交于 2020-01-24 18:44:29
简介 序列自动机是一个可以快速判断字符串 \(t\) 是否是字符串 \(s\) 的子串的一个算法。 构造 对 \(s\) 构造序列自动机,使用 \(Nxt_{i,j}\) 代表从第 \(i\) 个位置开始,字符 \(j\) 出现的第一个位置。我们倒着遍历更新即可。 int nxt[N][27]; void init(char *s){ int l=strlen(s); for(int i=0;i<26;i++) nxt[l][i]=INF; for(int i=l-1;i>=0;i--){ for(int j=0;j<26;j++){ nxt[i][j]=nxt[i+1][j]; } nxt[i][s[i]-'a']=i; } } 查询 设置初始指针 \(p\) 为-1,每次让 \(p\) 跳到 \(Nxt_{p+1,j}\) 上面, \(j\) 为当前查询的字符,如果 \(p\) 为 \(INF\) ,则说明找不到下一个字符,即 \(t\) 不是 \(s\) 的子串。 bool find(char *t){ int pos=-1; int l=strlen(t); for(int i=0;i<l;i++){ pos=nxt[pos+1][t[i]-'a']; if(pos==INF) return 0; } return 1; } 模板 struct sub_AM{ int

AC自动机模板

霸气de小男生 提交于 2020-01-24 14:44:27
AC自动机原理: 摘自 http://www.cnblogs.com/huangxincheng/archive/2012/12/02/2798317.html ,ORZ大牛 一:构建AC自动机 同样我也用网上的经典例子,现有say she shr he her 这样5个模式串,主串为yasherhs,我要做的就是哪些模式串在主串中出现过? 1: 构建trie树 如果看过我前面的文章,构建trie树还是很容易的。 2:失败指针 构建失败指针是AC自动机的核心所在,玩转了它也就玩转了AC自动机,失败指针非常类似于KMP中的next数组,也就是说, 当我的主串在trie树中进行匹配的时候,如果当前节点不能再继续进行匹配,那么我们就会走到当前节点的failNode节点继续进行 匹配,构建failnode节点也是很流程化的。 ①:root节点的子节点的failnode都是指向root。 ②:当走到在“she”中的”h“节点时,我们给它的failnode设置什么呢?此时就要走该节点(h)的父节点(s)的失败指针,一直回溯直 到找到某个节点的孩子节点也是当初节点同样的字符(h),没有找到的话,其失败指针就指向root。 比如:h节点的父节点为s,s的failnode节点为root,走到root后继续寻找子节点为h的节点,恰好我们找到了,( 假如还是没 有找到,则继续走该节点的failnode

图解AC自动机

假装没事ソ 提交于 2020-01-24 05:01:38
图解AC自动机 前言: 我们引出这样一个问题: 我想知道字符串 \(t\) 在字符串中 \(s\) 出现多少次/有没有出现? 那我们可以使用kmp算法求出 \(t\) 的next数组,之后 \(O(n)\) 匹配求解即可。 那如果把问题升级一下呢? 想知道字符串 \(t_1,t_2,...,t_n\) 在字符串 \(s\) 中出现了多少次/有没有出现? 这时候再用 \(kmp\) 算法,复杂度将达到 \(O(n^2)\) ,非常慢了。 这时候我们需要AC自动机。 AC自动机用于求解多个模式串与一个文本串的匹配问题。 AC自动机需要 提前知道所有需要匹配的字符串 。 可以想象成trie树上kmp。 开始图解: 假设说我们的模式串分别为: \(abcd,abd,bcd,cd\) 。 第一步:创建trie树 没啥好说的,建立trie就行了呗。 其中红色节点代表一个字符串的结尾。 第二步:构建失配指针(最重要的一步) 这一步的目的和kmp算法中求nex数组的目的是类似的。 对于kmp算法来说,是求next;对于AC自动机来说,是求fail指针。 \(fail(i):\) 以 \(i\) 节点为结尾的串的后缀与其他串有最大公共长度的前缀的结尾编号。 可能看到这里比较懵逼,没关系,模拟一下就好了。 首先看第一个字符串: \(abcd\) ,不存在任何一个其他子串的前缀与 \(abcd\)

编译原理(词法分析)

…衆ロ難τιáo~ 提交于 2020-01-22 09:05:09
文章目录 1.编译原理概述 2.词法分析 正规集 正规式 正规文法 自动机 已知集合求正规式、DFA; 已知正规式求DFA、集合; 已知DFA求正规式、集合; DFA的确定化、最小化。 1.编译原理概述 程序设计语言的翻译模式:编译、汇编;转换(预处理);反汇编、反编译;交叉编译、交叉汇编 静态语义错误(如分母不为0)在语义分析阶段可以被检测出来 词法分析里的坑点,因为词法分析只是识别记号,它并不会排查声明变量结构性错误,这个错误要到语法分析之中才可以被检查出来 动态语义错误编译过程中一般不会处理,只有到程序执行时才会发现 几个错误的典型实例 对程序语句的翻译主要考虑两类语句:声明语句和可执行语句,其中,对声明语句,主要是将所需要的信息正确地填入合理组织的 符号表 中;对可执行语句,则是 翻译成中间代码 在以阶段划分的编译器中, 符号表管理 和 出错处理 两个阶段的工作贯穿于编译器工作始终。 有两个因素使得有限自动机是不确定的,一个是 具有ε状态转移 ,另一个是对同一字符, 可能有多于一个的下一状态转移 词法分析器有四个作用,请给出其中的任意两个: 识别记号并交给语法分析器 / 滤掉源程序中的无用成分 / 处理与具体平台有关的输入 / 调用符号表管理器或出错管理器 语法分析器根据语法规则 识别出记号流中的结构 ,并 构造一棵能够正确反映该结构的语法树 。 检查输入中的错误

芝士:AC自动机

柔情痞子 提交于 2020-01-21 10:07:29
背景 为了解决字符串问题而出来的数据结构 前置芝士 Trie 就是通过树这种树形结构,充分利用LCP的树形结构 举个栗子: 我们有字符串: abd abe ab ba 他们的Trie长成这样 KMP 简单一句话而言: 继承革命烈火! 为何如此而言? 对于文本串,我们假设当前的元素为 \(i\) 对于模式串,我们假设当前的元素为 \(j\) 我们要考虑的其实就是 \(c_i\) 与 \(s_j\) 不相同 如果不相同,我们就要返回去从 \(i-j+2\) 开始匹配 但是,我们都已经虽然 \(c_i\neq s_j\) ,但是我们可以之前是匹配的啊 所以,我们可以不用退这么多 我们只需要知道当前的最长后缀与最长的哪一个前缀是一样的,再将 \(j\) 指过来就行了 乍一看时间复杂度好像没变 但是巨佬们说这样的方法均摊是 \(O(n)\) 还是不懂? 机房巨佬PPL的博客 # 做什么 给定n个模式串,求有多少个模式串在文本串中出现过 思路 预处理 将模式串建成Trie 主要想法 借用KMP的思想,我们每一次的匹配尽量使用已经有的最长前缀 fail指针 做什么 如果 \(fail_i==j\) 那么 \(root\) 到 \(j\) 的字符串是 \(root\) 到 \(i\) 的字符串的一个后缀 所以你明白了吧,通过这个fail,我们可以每次不从根节点开始比较,这大大减少了时间复杂度

编译原理学习指导 - ★★★TINYUE的专栏★★★ - CSDNBlog

房东的猫 提交于 2020-01-21 02:53:18
编译原理学习指导 编译原理是计算机专业课程中最难同时也是最有挑战性的一门,理论上高度抽象,而且要求扎实的数学功底,在实践上也对数据结构的知识要求比较高.但是编译原理又是计算机科学中最为基础和重要的,类似于高等数学在理工科中的地位,所以今天粗略的跟大家谈谈这门课程的学习. 一、为什么学编译原理? 1、 编译原理蕴涵着计算机学科中解决问题的思路、抽象问题和解决问题的方法; 2、 编译原理课程的学习有利于加深对程序语言的理解,可以帮助你更加快速的掌握新的语言工具; 3、 课程中包含了很多软件技术,这对于以后从事软件设计是很有帮助的. 二、编译原理主要内容提要 (一)编译程序的功能、工作过程、结构以及构造方法 计算机只能读懂0或者1,而我们用高级语言编写的程序(原程序)是抽象的符号化了的东西,为了让计算机读懂我们写的程序,必须把我们 书写的程序翻译成某台机器能够读懂的(机器)语言(目标程序),这就是翻译程序的作用.翻译程序进行的是等价的翻译,意思就是说目标程序 和原程序在功能上是等价的;翻译程序有两种方式:“编译”、“解释”,区别在于是否生成目标代码,解释方式下,是直接执行源程序本身的 或者与源程序等价的中间程序,并不生成目标代码,而编译方式下,必须生成目标代码. 编译方式的特点①源程序的执行是分阶段的:编译阶段和执行阶段(若编译生成的目标程序是汇编语言程序,则在两者之间还有一个汇编 阶段

[算法模版]回文树

折月煮酒 提交于 2020-01-18 20:31:14
回文树 本文全文引自 yijan ,特此鸣谢。 回文树,也就是回文自动机,PAM(Palindrome automaton) 是一个处理回文串的有力工具。然而这个东西比SAM简单多了。。 (它可能比 manacher 要强得多?) 回文自动机有两个根,也就是说其实是有两个树的,一个存储长度为奇数的回文串一个存储长度为偶数的回文串。 回文自动机上的每一个节点表示一个本质不同的回文串。也就是说回文自动机上的节点个数就是本质不同的回文串个数。 一些定义 $ len[p] $ 表示 $ p $ 节点所代表回文串长度 $ fail[p] $ 表示 $ p $ 节点的 最长回文后缀 所在的节点。 $ son[p][c] $ 表示 $ p $ 节点代表回文串两边分别加上字母 $ c $ 得到的回文串的节点。 由于回文树的构造方法类似后缀自动机采用增量法,有一个重要的结论: 每次在当前的字符串结尾添加一个字母,如果新增了回文串,那么新增的本质不同回文串必然是添加后的字符串的最长回文后缀这一个。 证明很简单,画图有: 如果最左边的红色和最右边的红色构成的是最长回文后缀,并且有一个更短的后缀,它一定已经出现过了。 同时这也证明了本质不同的回文个数是 $ O(n) $ 的。 构造回文树 首先,初始状态只有两个点,$ t_0,t_1 $ 分别表示奇数回文串个数和偶数回文串个数。我们有 $ len[t_0]