浅谈Aho-Corasick automaton(AC自动机)

Aho-Corasick automaton是什么?

要学会AC自动机,我们必须知道什么是Trie,也就是字典树。Trie树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。

首先我们要知道trie,而且要知道KMP,这样就可以学AC自动机了!

其实AC自动机就是trie和KMP的结合体。主要构建trie后使用KMP的主导思想构建fail边,每次匹配与KMP相似。

下面我们看看如何构造fail边。

fail边就是类似KMP中的next数组,在失配的时候能够指向的地方。
这里写图片描述

这就是一颗trie树,那么我们应该怎么去连fail边呢?

首先我们知道root的fail边是连向自己的,而且所有与root直接相连的点fail都指向root。
这里写图片描述
然后每个点,看看自己父亲的fail边指向的位置的点是否有一个与它长的一样的儿子,如果有,那么连上,否则继续找fail边,直到root为止(注意这个过程我们用bfs实现)。所以最终连完的fail边就是这样:
这里写图片描述
这样我们只需要每一位去匹配就好了。

有人问,怎么匹配:

举个栗子:
用上面的图:
这里写图片描述
假设原串是:ahershe,这棵trie上有his,her,he,she。
我们从root开始,先查找root点有没有当前字母的儿子a,有那么指针x指到h点上,这样一直匹配;如果没有,那么就直接跳到当前点的fail边上,这样保证前面匹配的全都是相同的,直到有这样的儿子或者已经到了root并且没有这样的儿子为止。
注意每跳一个点就必须从当前点遍历一遍它的fail边直到root的边集,就是说沿着fail边跳一直到root为止,这是为了避免当前点没有被标记,但是在它fail边到达root的路径上有被标记的点。

Exanple

【GDOI2013模拟4】贴瓷砖

Description

A镇的主街是由N个小写字母构成,镇长准备在上面贴瓷砖,瓷砖一共有M种,第i种上面有Li个小写字母,瓷砖不能旋转也不能被分割开来,瓷砖只能贴在跟它身上的字母完全一样的地方,允许瓷砖重叠,并且同一种瓷砖的数量是无穷的。
问街道有多少字母(地方)不能被瓷砖覆盖。

Input

第一行输入街道长度N(1<=N<=300,000)。
第二行输入N个英文小写字母描述街道的情况。
第三行输入M(1<=M<=5000),表示瓷砖的种类。
接下来M行,每行描述一种瓷砖,长度为Li(1<=Li<=5000),全部由小写字母构成。

Output

输出有多少个地方不能被瓷砖覆盖。

Sample Input

输入1:

6

abcbab

2

cb

cbab

输入2:

4

abab

2

bac

baba

输入3:

6

abcabc

2

abca

cab

Sample Output

输出1:

2

输出2:

4

输出3:

1

Data Constraint

N(1<=N<=300,000)

Solution

我们把原字符串每一位都进行匹配,然后首先预处理出trie中每一个点对应所有fail边中最大的长度,然后匹配的时候记录下每一位中能够覆盖到的最大长度,最后用线段树维护(当然你可以直接用差分约束)。

Code

#include<cstdio>
#include<iostream>
#include<cstring>
#define mo 1000010
using namespace std;
struct Moon{int fail,num,maxl;}point[4000010];
int son[4000010][27];
int lengt_max[300010],length[300010];
char s[300010],ch[300010];
int len,n,root,sz; 
int d[mo];
int f[300010*4],tag[300010*4];
void make_trie(char s1[300010],int len1,int t,int x,int id)
{if(t>len1) {point[x].num=id;point[x].maxl=length[id];return;}   if(!son[x][s1[t]-96]){son[x][s1[t]-96]=++sz;++son[x][0];make_trie(s1,len1,t+1,sz,id);   }else make_trie(s1,len1,t+1,son[x][s1[t]-96],id);
}
void build_fail()
{int i,x,k,head=0,tail=0;for (i=1;i<=26&&tail<son[root][0];++i)if(son[root][i]) {d[++tail]=son[root][i];point[son[root][i]].fail=root;}while(head!=tail){head=head%mo+1;x=d[head];if(!son[x][0]) continue;for (i=1;i<=26;++i)if(son[x][i]){tail=tail%mo+1;d[tail]=son[x][i];k=point[x].fail;while(k!=root){if(son[k][i]) break;k=point[k].fail;if(k==root&&!son[k][i]) break;}if(son[k][i]) point[son[x][i]].fail=son[k][i];else point[son[x][i]].fail=root;point[son[x][i]].maxl=max(point[son[x][i]].maxl,point[point[son[x][i]].fail].maxl);}}
}
void Check()
{int x=root,k;for (int i=1;i<=len;){if(son[x][s[i]-96]) {x=son[x][s[i]-96];  lengt_max[i]=max(lengt_max[i],point[x].maxl);++i;}   else x=point[x].fail;if(x==root&&!son[x][s[i]-96]) ++i;}
} 
void change(int v,int l,int r,int x,int y)
{if(l==x&&r==y){tag[v]=1;f[v]=r-l+1; return;}int mid=(l+r)/2;if(tag[v]){tag[v*2]=1,f[v*2]=mid-l+1;tag[v*2+1]=1,f[v*2+1]=r-mid;tag[v]=0;}if(y<=mid) change(v*2,l,mid,x,y);else if(x>mid) change(v*2+1,mid+1,r,x,y);else change(v*2,l,mid,x,mid),change(v*2+1,mid+1,r,mid+1,y);f[v]=f[v*2]+f[v*2+1];
}
int main()
{scanf("%d",&len);scanf("%s",s+1);scanf("%d",&n);int i,j;root=sz=point[1].fail=1;for (i=1;i<=n;++i){scanf("%s",ch+1);length[i]=strlen(ch+1);make_trie(ch,length[i],1,root,i);}build_fail();Check();for (i=1;i<=len;++i) if(lengt_max[i]) change(1,1,len,i-lengt_max[i]+1,i);printf("%d\n",len-f[1]);
}

转载于:https://www.cnblogs.com/Chandery/p/11332808.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/248263.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javaScript第七天(2)

javaScript基础 ☞ 对象其他部分 [理解] 自定义构造函数创建对象[掌握] //继续简化 自定义构造函数 function People(uName, uAge) {this.uName uName;this.uAge uAge; } // 如何通过自定义构造函数创建对象? var zs new People(张三, 20); console.log(zs);注意事项: 自定…

数据挖掘、机器学习书籍推荐!!

强烈推荐&#xff1a;《机器学习》 (西瓜书) 入门读物&#xff1a; 《深入浅出数据分析》 这书挺简单的&#xff0c;基本的内容都涉及了&#xff0c;说得也比较清楚&#xff0c;最后谈到了R是大加分。难易程度&#xff1a;非常易。 《啤酒与尿布》 通过案例来说事情&#xff0c…

楼兰图腾(权值线段树)

在完成了分配任务之后&#xff0c;西部314来到了楼兰古城的西部。 相传很久以前这片土地上(比楼兰古城还早)生活着两个部落&#xff0c;一个部落崇拜尖刀(‘V’)&#xff0c;一个部落崇拜铁锹(‘∧’)&#xff0c;他们分别用V和∧的形状来代表各自部落的图腾。 西部314在楼兰古…

js(Dom+Bom)第一天(1)

JavaScript-DOM&#xff08;BOM&#xff09;操作 核心知识 获取页面元素事件设置样式 学习目标 能够使用id名,标签名等方式获取页面中元素能够给标签注册点击事件,并实现对应效果能够给标签通过js方式设置样式 JavaScript组成 ECMASCRIPT (基础语法) DOM&#xff08;文档对…

[HZNOI #koishi] Magic

[HZNOI #514] Magic 题意 给定一个 \(n\) 个点 \(m\) 条边的有向图, 每个点有两个权值 \(a_i\) 和 \(b_i\), 可以以 \(b_i\) 的花费把第 \(i\) 个点的 \(a_i\) 变成 \(0\). 最后每个点 \(i\) 产生的花费为所有从 \(i\) 出发能通过一条有向边直接到达的点 \(j\) 的 \(a_j\) 的 \…

同步与异步

同步&#xff1a; 做完一件事&#xff0c;再做另一件 煮好水&#xff0c;再拆泡面包装 异步&#xff1a; 可以同时做好几个任务 烧水&#xff0c;打开火之后&#xff0c;先去拆泡面包装&#xff0c;等水开了&#xff0c;再停下拆包装&#xff0c;去关掉火。。。。。 转载于:htt…

js(Dom+Bom)第一天(2)

webAPI 00-复习 内置对象中的方法 01-JavaScript组成 知识点-ECMASCRIPT 重点回顾 存储容器 变量数组对象 逻辑语法 分支语句循环语句switch语句 知识点-BOM 概念 Browser Object Model (浏览器器对象模型) 操作浏览器将浏览器看做是一个对象.作用 通过js操作浏览器中相…

mysql 主主复制的配置流程

1、先关闭B&#xff0c;把A的数据导出来&#xff0c;mysqldump -hlocalhost -uroot -p123456 --database ibprpu >ibprpu.sql2、关闭A&#xff0c;启动B&#xff0c;进入mysql建立一个新的数据库 create database ibprpu3、导入数据库 mysql -hlocalhost -uroot -p123456 &l…

华为架构师8年经验谈:从单体架构到微服务的服务化演进之路

本次分享的技术大纲如下&#xff1a; 传统应用开发面临的挑战服务化实践服务化不是银弹服务化架构的演进方向一 、传统应用开发面临的挑战 挑战1-- 研发成本高 主要体现在如下几个方面&#xff1a; 代码重复率高在实际项目分工时&#xff0c;开发都是各自负责几个功能&#xff…

轮播图制作(1)

轮播图制作 <body><div><img src"img/1.jpg" class"imgs" alt""><a href"#" class"left"><</a> //此处的箭头也可以用图标做出来<a href"#" class"right">>…

StringUtils工具类的常用方法

StringUtils 方法的操作对象是 java.lang.String 类型的对象&#xff0c;是 JDK 提供的 String 类型操作方法的补充&#xff0c;并且是 null 安全的(即如果输入参数 String 为 null 则不会抛出 NullPointerException &#xff0c;而是做了相应处理&#xff0c;例如&#xff0c…

struts2+extjs文件上传完整实现(攻克了上传中的各种问题)

版权声明&#xff1a;本文为博主原创文章。未经博主同意不得转载。 https://blog.csdn.net/shanhuhau/article/details/28617999 首先须要引入上传控件 <script type"text/javascript" src"<%basePath%>/js/ext/examples/ux/fileuploadfield/FileUploa…

放大镜制作(1)

放大镜制作 <div class"box" id"box"><!--左侧的盒子--><div class"small"><!--图片--><img src"images/big.jpg" width"350" class"aaa" alt""/><!--黄色小盒子--&…

.NET Framework 2.0 组件和非托管代码与交互操作详解(转)

.NET Framework 将促进与 COM 组件、COM 服务、外部类型库和许多操作系统服务的交互操作。在托管和非托管对象模型之间&#xff0c;数据类型、方法签名和错误处理机制都存在差异。为了简化 .NET Framework 组件和非托管代码之间的互用并便于进行移植&#xff0c;公共语言运行时…

git 删除远程分支和本地分支

删除远程分支和本地分支 https://www.cnblogs.com/luosongchao/p/3408365.html 将远程git仓库里的指定分支拉取到本地&#xff08;本地不存在的分支&#xff09; https://www.cnblogs.com/hamsterPP/p/6810831.html 转载于:https://www.cnblogs.com/mafeng/p/10619419.html

从零开始实现ASP.NET Core MVC的插件式开发(四) - 插件安装

标题&#xff1a;从零开始实现ASP.NET Core MVC的插件式开发(四) - 插件安装 作者&#xff1a;Lamond Lu 地址&#xff1a;https://www.cnblogs.com/lwqlun/p/11343141.html 源代码&#xff1a;https://github.com/lamondlu/Mystique 前情回顾 从零开始实现ASP.NET Core MVC的插…

立体导航翻转案例

<div class"box"><!-- 立方体 --><ul><li><img src"img1/1.jpg" alt""></li><li><img src"img1/2.jpg" alt""></li><li><img src"img1/3.jpg" a…

Uncontrolled memory mapping in camera driver (CVE-2013-2595)

版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主同意不得转载。https://blog.csdn.net/hu3167343/article/details/34434235 /* 本文章由 莫灰灰 编写&#xff0c;转载请注明出处。 作者&#xff1a;莫灰灰 邮箱&#xff1a; minzhenfei163.com */ 1漏洞描写…

表格隔行变色

<body><table border"0" align"center" cellspacing"1" cellpadding"0"><caption>恭喜发财</caption><thead><tr><th>代码</th><th>名称</th><th>最新公布净值<…

启动Cognos时报0106错误

1. 问题描述 启动Cognos失败&#xff0c;报错代码为0106。 2. 问题分析 是jdk版本不兼容。 3. 解决方案 方案一&#xff1a;更换jdk1.6&#xff0c;可以使用免安装版&#xff0c;不需要卸载原有的jdk将java_home的路径替换成jdk1.6的路径。 方案二&#xff1a;使用Cognos自带jd…