什么是AC自动机?

百度百科

Aho-Corasick automaton,该算法在1975年产生于贝尔实验室,是著名的多模匹配算法。

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

AC自动机有什么作用?

快速寻找多个字串与原串的关系,是多个字符串的kmp匹配算法

怎么实现AC自动机?

①trie字典树部分

这里只需要进行一个insert函数书写即可,把每个字串插入到trie树中,不同于字典树模板,这个insert函数需要记录词尾。

具体代码

void insert(string a)
{
int rt=0;
for(int i=0;i<a.size();i++)
{
int id=a[i]-'a';
if(!trie[rt][id])
trie[rt][id]=++cnt;
rt=trie[rt][id];
}
bk[rt]++;
}

②KMP部分

build函数

①枚举根节点的各个孩子如果存在就把他们入队

queue<int> q;
memset(fail,0,sizeof(fail));
for(int i=0;i<26;i++)
if(trie[0][i])
q.push(trie[0][i]);

②BFS进行搜索

转载于洛谷日报第44期

下面介绍构建fail指针的基础思想:(强调!基础思想!基础!)

构建fail指针,可以参考KMP中构造next数组的思想。

我们利用部分已经求出fail指针的结点推导出当前结点的fail指针。具体我们用BFS实现:

考虑字典树中当前的节点u,u的父节点是p,p通过字符c的边指向u。

假设深度小于u的所有节点的fail指针都已求得。那么p的fail指针显然也已求得。

我们跳转到p的fail指针指向的结点fail[p];

如果结点fail[p]通过字母cc连接到的子结点w存在:

则让u的fail指针指向这个结点w(fail[u]=w)。

相当于在pp和fail[p]后面加一个字符cc,就构成了fail[u]。

如果fail[p]通过字母cc连接到的子结点w不存在:

那么我们继续找到fail[fail[p]]指针指向的结点,重复上述判断过程,一直跳fail指针直到根节点。

如果真的没有,就令fail[u]=根节点。

如此即完成了fail指针的构建。

while(!q.empty())
{
int k=q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(trie[k][i])
{
fail[trie[k][i]]=trie[fail[k]][i];
q.push(trie[k][i]);
}
else
trie[k][i]=trie[fail[k]][i];
}
}

完整代码

void build()
{
queue<int> q;
memset(fail,0,sizeof(fail));
for(int i=0;i<26;i++)
if(trie[0][i])
q.push(trie[0][i]);
while(!q.empty())
{
int k=q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(trie[k][i])
{
fail[trie[k][i]]=trie[fail[k]][i];
q.push(trie[k][i]);
}
else
trie[k][i]=trie[fail[k]][i];
}
}
}

个人的理解是,这一部分首先把根的子节点入队,然后bfs建立字典图,感觉跟并查集有点类似

③查询部分

这里没有什么好说的,先和并查集的感觉,找到最后的叶子节点然后就是一顿查询fail,这里的查询是查询字串总共有多少个出现在了原串中,所以要bk[j]=-1,然后判断条件还得加上bk[j]!=-1

int search(string a)
{
int rt=0,ans=0;
for(int i=0;i<a.size();i++)
{
rt=trie[rt][a[i]-'a'];
for(int j=rt;j&&bk[j]!=-1;j=fail[j])
ans+=bk[j],bk[j]=-1;
}
return ans;
}

完整代码(洛谷 P3808 【模板】AC自动机(简单版))

#include <bits/stdc++.h>
using namespace std;
int trie[10000000][30];
int bk[10000000];
int fail[10000000];
int cnt;
void insert(string a)
{
int rt=0;
for(int i=0;i<a.size();i++)
{
int id=a[i]-'a';
if(!trie[rt][id])
trie[rt][id]=++cnt;
rt=trie[rt][id];
}
bk[rt]++;
}
void build()
{
queue<int> q;
memset(fail,0,sizeof(fail));
for(int i=0;i<26;i++)
if(trie[0][i])
q.push(trie[0][i]);
while(!q.empty())
{
int k=q.front();
q.pop();
for(int i=0;i<26;i++)
{
if(trie[k][i])
{
fail[trie[k][i]]=trie[fail[k]][i];
q.push(trie[k][i]);
}
else
trie[k][i]=trie[fail[k]][i];
}
}
}
int search(string a)
{
int rt=0,ans=0;
for(int i=0;i<a.size();i++)
{
rt=trie[rt][a[i]-'a'];
for(int j=rt;j&&bk[j]!=-1;j=fail[j])
ans+=bk[j],bk[j]=-1;
}
return ans;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
while(n--)
{
string a;
cin>>a;
insert(a);
}
build();
string a;
cin>>a;
cout<<search(a);
}

浅谈AC自动机模板的更多相关文章

  1. 浅谈AC自动机

    写在前面:从10月23日开始写这篇博文,离NOIP2018只有十多天了.坚持不停课的倔强蒟蒻(我)尽量每天挤时间多搞一搞信竞(然而还要准备期中考试).NOIP争取考一个好成绩吧. 一.简介 AC自动机 ...

  2. HDU 2222 AC自动机模板题

    题目: http://acm.hdu.edu.cn/showproblem.php?pid=2222 AC自动机模板题 我现在对AC自动机的理解还一般,就贴一下我参考学习的两篇博客的链接: http: ...

  3. Match:Keywords Search(AC自动机模板)(HDU 2222)

    多模匹配 题目大意:给定很多个字串A,B,C,D,E....,然后再给你目标串str字串,看目标串中出现多少个给定的字串. 经典AC自动机模板题,不多说. #include <iostream& ...

  4. HDU 3065 (AC自动机模板题)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3065 题目大意:多个模式串,范围是大写字母.匹配串的字符范围是(0~127).问匹配串中含有哪几种模 ...

  5. HDU 2896 (AC自动机模板题)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2896 题目大意:多个模式串.多个匹配串.其中串的字符范围是(0~127).问匹配串中含有哪几个模式串 ...

  6. HDU 2222(AC自动机模板题)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2222 题目大意:多个模式串.问匹配串中含有多少个模式串.注意模式串有重复,所以要累计重复结果. 解题 ...

  7. HDU 2222 (AC自动机模板题)

    题意: 给一个文本串和多个模式串,求文本串中一共出现多少次模式串 分析: ac自动机模板,关键是失配函数 #include <map> #include <set> #incl ...

  8. hdu 2222 Keywords Search ac自动机模板

    题目链接 先整理一发ac自动机模板.. #include <iostream> #include <vector> #include <cstdio> #inclu ...

  9. KMP与AC自动机模板

    HDU 1711 Number Sequence(KMP模板题) http://acm.hdu.edu.cn/showproblem.php?pid=1711 #include<bits/std ...

随机推荐

  1. Codeforces Round #228 (Div. 2) C. Fox and Box Accumulation

    C. Fox and Box Accumulation time limit per test 1 second memory limit per test 256 megabytes input s ...

  2. Java 反射 —— 运行时的类型信息

    1. 反射机制的由来 RTTI 机制可以告知某个对象的确切类型,但有一个前提,该类型在编译时必须已知(编译器在编译时打开和检查 .class 文件以获取类型信息).似乎是个很宽松的限制,但假如你获取了 ...

  3. flask核心对象Flask实例初探

    flask的核心程序就两个: werkzegu(WSGI)库,封装了http.web通信等最关键的wsgi功能②Jinja2是Python下一个被广泛应用的模版引擎,方便了html模板的创建和使用 而 ...

  4. gitlab gerrit jenkins CI/CD环境集成

    http://blog.csdn.net/williamwanglei/article/details/38498465

  5. EasyUI Datagrid 分页显示(客户端)

    转自:https://blog.csdn.net/metal1/article/details/17536185 EasyUI Datagrid 分页显示(客户端) By ZYZ 在使用JQuery ...

  6. tar zxvf 解压文件提示错误

    1.tar -zxvf 提示错误 2. 查看文件之后发现是html格式的.file **(文件名) 3.原来是直接之前sudo wget url ...url连接错误了. 这个url直接在jdk哪里, ...

  7. ViewModel、ViewData、ViewBag、TempData、Session之间的区别和各自的使用方法

    ViewModel    ViewModel 是一个用来渲染 ASP.NET MVC 视图的强类型类,可用来传递来自一个或多个视图模型(即类)或数据表的数据.可将其看做一座连接着模型.数据和视图的桥梁 ...

  8. js工作备注

    { field : 'state', title : '事件状态', align: 'center', width : 120, formatter : function(value, row, in ...

  9. bzoj 1652: [Usaco2006 Feb]Treats for the Cows【区间dp】

    裸的区间dp,设f[i][j]为区间(i,j)的答案,转移是f[i][j]=max(f[i+1][j]+a[i](n-j+i),f[i][j-1]+a[j]*(n-j+i)); #include< ...

  10. 洛谷P4241 采摘毒瘤

    传送门 完了我连背包都不会了…… 考虑暴力,先枚举最小的数是哪个,设大小为$d_i$,个数为$k_i$,所有比它小的数的总和是$sum$,然后把所有比它小的全都装进背包,它以及比他大的做一个多重背包, ...