(并不能自动AC)

介绍:

Aho-Corasick automaton,最经典的处理多个模式串的匹配问题。

是kmp和字典树的结合。

精髓与灵魂:

①利用trie处理多个模式串

②引入fail指针。节点x的fail表示,trie中最大的某个前缀等于x到根节点字符串后缀的节点位置。

fail类比于kmp的nxt数组,可以在失配的时候,O(1)找到最大的可能能继续匹配的位置。

所以,ac自动机可看做多个kmp

步骤:(完整代码在下面)

①建trie树。插入模式串。

void ins(char *s){
int len=strlen(s+);
int now=;
for(int i=;i<=len;i++){
int x=s[i]-'A';
if(!a[now][x]) a[now][x]=++cnt;
now=a[now][x];
}
exi[now]=;
}

②trie上建ac自动机。

void build(){
queue<int>q;
for(int i=;i<;i++){
if(a[][i]) fail[a[][i]]=,q.push(a[][i]);
}
while(!q.empty()){
int x=q.front();q.pop();
exi[x]|=exi[fail[x]];
for(int i=;i<;i++){
if(a[x][i]){
fail[a[x][i]]=a[fail[x]][i];
q.push(a[x][i]);
}
else{
a[x][i]=a[fail[x]][i];
}
}
}
}

用bfs来建造,并且,即时转移fail指针。

fail指针的转移正确性:

因为bfs是分层加入元素,而fail至少让字符串长度-1,所以之前的fail[x]的各种信息都处理完毕了。

并且,由于fail的定义,所以能在fail[x][i]往下转移,一定就是最优的。

这里有个小优化:

else{a[x][i]=a[fail[x]][i];}

如果x没有i这个儿子,那么就直接指向它fail指针位置的儿子。

这样子,在之后的if(a[x][i])中,可以直接走一次fail[x]的儿子就可以找到真正的fail[a[x][i]]了。

因为,如果fail没有这个儿子,不加这个优化还要继续跳fail,复杂度没有保证了。

这样,就类似于并查集的路径压缩思想,直接指到最长的有这个儿子的点了。

(语言表达不好,自行画图理解吧。。。)

完整代码:

struct node{
int a[N*N][26],cnt;
int fail[N*N];
bool exi[N*N];
void init(){
memset(a,0,sizeof a);memset(exi,0,sizeof exi);
cnt=0;memset(fail,0,sizeof fail);
}
void ins(char *s){
int len=strlen(s+1);
int now=0;
for(int i=1;i<=len;i++){
int x=s[i]-'A';
if(!a[now][x]) a[now][x]=++cnt;
now=a[now][x];
}
exi[now]=1;
}
void build(){
queue<int>q;
for(int i=0;i<26;i++){
if(a[0][i]) fail[a[0][i]]=0,q.push(a[0][i]);
}
while(!q.empty()){
int x=q.front();q.pop();
exi[x]|=exi[fail[x]];
for(int i=0;i<26;i++){
if(a[x][i]){
fail[a[x][i]]=a[fail[x]][i];
q.push(a[x][i]);
}
else{
a[x][i]=a[fail[x]][i];
}
}
}
}
}ac;

另外,我们ac自动机上节点上,也可以加上其他的标记。

例题:

[JSOI2007]文本生成器

Description:

给n个模式串,求有多少个长度为m的文章,至少包含一个模式串

Solution:

Ac自动机的标志很明显,多个模式串,一个主串。

Ac自动机dp的状态很套路,一般就是匹配到j位置,怎么怎么样。。

设f[i][j],前i个字符,匹配到AC自动机的j位置,没出现一个模式串的方案数。(最后总方案-没出现一个方案,差分)

每个点有一个exi布尔数组,表示匹配到这个点,这个点所代表的前缀(可以是一个完整模式串)是否已经包含了至少一个模式串。

插入的时候,末尾exi=1,bfs的时候,exi[x]|=exi[fail[x]]即可。正确性同bfs分层图性质。

然后判断,直接转移就好了。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=+;
const int mod=;
struct node{
int a[N*N][],cnt;
int fail[N*N];
bool exi[N*N];
void init(){
memset(a,,sizeof a);memset(exi,,sizeof exi);
cnt=;memset(fail,,sizeof fail);
}
void ins(char *s){
int len=strlen(s+);
int now=;
for(int i=;i<=len;i++){
int x=s[i]-'A';
if(!a[now][x]) a[now][x]=++cnt;
now=a[now][x];
}
exi[now]=;
}
void build(){
queue<int>q;
for(int i=;i<;i++){
if(a[][i]) fail[a[][i]]=,q.push(a[][i]);
}
while(!q.empty()){
int x=q.front();q.pop();
exi[x]|=exi[fail[x]];
for(int i=;i<;i++){
if(a[x][i]){
fail[a[x][i]]=a[fail[x]][i];
q.push(a[x][i]);
}
else{
a[x][i]=a[fail[x]][i];
}
}
}
}
}ac;
int n,m;
int f[N][N*N];
char s[N];
int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++){
scanf("%s",s+);
ac.ins(s);
}
ac.build();
int tot=ac.cnt;
f[][]=;
for(int i=;i<=m-;i++){
for(int j=;j<=tot;j++){
if(!ac.exi[j]){
for(int k=;k<;k++){
if(!ac.exi[ac.a[j][k]]){
f[i+][ac.a[j][k]]=(f[i+][ac.a[j][k]]+f[i][j])%mod;
}
}
}
}
}
long long ans=;
for(int i=;i<=m;i++){
ans=(ans*)%mod;
}
for(int i=;i<=tot;i++){
if(!ac.exi[i]){
ans=(ans-f[m][i]+mod)%mod;
}
}
printf("%lld",ans);
return ;
}

为什么要记录AC自动机上匹配到的状态呢?

因为,单纯记录这一位是哪个字符肯定不能判断是否包含。

而AC自动机本身的fail,就蕴含了所有的可能包含的位置。只要不断跳fail即可。

相当于该状态已经包罗万象。

因为fail的定义,也不会包含更多,不会包含更少。

所以对于匹配问题再适合不过了。

AC自动机dp出题人出烦了之后,

就开始出一些涉及AC自动机形态的题目,更贴近算法本身。

基本开刀处都是fail指针(AC自动机的精髓嘛)

[POI2000]病毒

这是一个利用fail指针构可能可以和trie树构成环的特性。从而构造出无限长的串。

[NOI2011]阿狸的打字机——AC自动机之fail树的利用

这个题目恰好相反,把fail树和trie树都利用起来,并且离线处理。

这两个题目都是值得思考总结的。都利用了fail的性质,但是都没有直接使用fail指针。妙哉!

AC自动机——多个kmp匹配的更多相关文章

  1. ac自动机暴力跳fail匹配——hdu5880

    很简单的题,ac自动机里再维护一个len表示每个状态的串长,用s去query时每到一个结点都要暴力跳fail,因为有可能这个结点不是,但是其fail是危险结点,找到一个就直接break 再用个差分数组 ...

  2. Codeforces 590E - Birthday(AC 自动机+Dilworth 定理+二分图匹配)

    题面传送门 AC 自动机有时只是辅助建图的工具,真的 首先看到多串问题,果断建出 AC 自动机.设 \(m=\sum|s_i|\). 不难发现子串的包含关系构成了一个偏序集,于是我们考虑转化为图论,若 ...

  3. ac自动机(tree+kmp模板)

    Keywords Search Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others ...

  4. hdu1686 Oulipo KMP/AC自动机

    The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter 'e ...

  5. KMP与AC自动机

    KMP算法主要思想就是预处理出失配函数, 从而减少匹配失败时的回溯, 复杂度是$\Theta(m+n)$, 已达到理论下界 c++代码如下 int n, f[N]; char t[N], p[N]; ...

  6. [Alg] 文本匹配-多模匹配-AC自动机

    1. 简介 AC自动机是一种多模匹配的文本匹配算法. 如果采用naive的方法,即依次比较文本串s中是否包含模式串p1, p2,...非常耗时.考虑到这些模式串中可能具有相同子串,可以利用已经比较过的 ...

  7. 使用AC自动机解决文章匹配多个候选词问题

    解决的问题 KMP算法用于单个字符串匹配,AC自动机用于文章中匹配多个候选词. 流程 第一步,先将候选词先建立前缀树. 第二步,以宽度优先遍历的方式把前缀树的每个节点设置fail指针, 头节点的fai ...

  8. 【hdu3247-Resource Archiver】位压DP+AC自动机+SPFA

    题意:给定n个文本串,m个病毒串,文本串重叠部分可以合并,但合并后不能含有病毒串,问所有文本串合并后最短多长. (2 <= n <= 10, 1 <= m <= 1000) 题 ...

  9. 【暑假】[实用数据结构] AC自动机

    Aho-Corasick自动机  算法: <功能> AC自动机用于解决文本一个而模板有多个的问题. AC自动机可以成功将多模板匹配,匹配意味着算法可以找到每一个模板在文本中出现的位置. & ...

随机推荐

  1. 20155321 《网络攻防》 Exp8 Web基础

    20155321 <网络攻防> Exp8 Web基础 基础问题回答 什么是表单? 表单是主要负责数据采集功能.主要是以下三个部分构成: 表单标签:包含处理表单数据所用的程序的URL以及数据 ...

  2. HTTPUTILS

    maven依赖 <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId&g ...

  3. EZ 2017 12 30 2018noip第二次膜你赛

    去年的比赛了,然而今天才改好. 总体难度适中,有大佬AK. 主要是自己SB第二题没想出来,然后又是可怜的100来分. T1 一道二分+数学的题目. 我们可以二分叫的次数,然后用公式(等差数列,公差都是 ...

  4. [清华集训2015 Day1]玛里苟斯-[线性基]

    Description Solution 考虑k=1的情况.假设所有数中,第i位为1的数的个数为x,则最后所有的子集异或结果中,第i位为1的个数为$(C_{k}^{1}+C_{k}^{3}+...)$ ...

  5. linux 定时器原理

    内核定时器:    unsigned long timeout = jiffies + (x * HZ);    while(1) {        // Check the condition.   ...

  6. 用C++实现一个Brainfuck解释器

    Brainfuck是一种极小化的计算机语言,只含有8种运算符,由于fuck在英语中是脏话,这种语言有时被称为brainfck或brainf**,甚至被简称为BF.正如它的名字所暗示,brainfuck ...

  7. MVC5.0知识点梳理

    我们在使用MVC的时候或许总是在使用着自己一直熟悉的知识点去实现已有的功能,多梳理一些知识点让每种功能的实现方式可以多样化. 我们在开发小型系统时总是使用微软MVC的脚手架功能,比如路由可能就是使用了 ...

  8. TensorFlow 实现线性回归

    1.生成高斯分布的随机数 导入numpy模块,通过numpy模块内的方法生成一组在方程 y = 2 * x + 3 周围小幅波动的随机坐标.代码如下: import numpy as np impor ...

  9. 开源微信Http协议Sdk【实现登录/获取好友列表/修改备注/发送消息】

    基于微信Http协议封装的一个Sdk,目前实现了以下功能:. 1:扫码登录(检测二维码扫描状态) 2:获取最近联系人.群组.所有联系人 3:修改好友备注 4:给好友发送消息 暂且这么多,也没多余的时间 ...

  10. 2014.9.11 Research Meeting Report

    Dear All: Yesterday when we read INFOCOM papers, you have seen how damage it is to have careless wri ...