什么是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. HDU 5308 I Wanna Become A 24-Point Master(2015多校第二场)

    I Wanna Become A 24-Point Master Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 ...

  2. JFreeChart自我总结

    想飞就别怕摔 大爷的并TM骂人 JFreeChart自我总结 1.饼图.柱状图.折线图生成的工具类   1 package com.text.util;  2   3 import java.awt. ...

  3. POJ 1330 LCA裸题~

    POJ 1330 Description A rooted tree is a well-known data structure in computer science and engineerin ...

  4. Flink源码阅读(1.7.2)

    目录 Client提交任务 flink的图结构 StreamGraph OptimizedPlan JobGraph ExecutionGraph flink部署与执行模型 Single Job Jo ...

  5. sql server数据库占用cpu太大,使用sys.dm_exec_query_stats查询优化

    查询sql语句占用 CPU详细信息: SELECT (SELECT TOP 1 SUBSTRING(s2.text,statement_start_offset / 2+1 , ( (CASE WHE ...

  6. shiro vue 前后端分离中模拟登录遇到的坑

    系统采用jeeplus框架(ssm+redis+shiro+mongodb+redis),默认是了JSP未做前后端分离,由于业务需要已经多终端使用的需求(H5.小程序等),需要实现前后端分离.但是由于 ...

  7. U - Relatives(欧拉函数)

    Description Given n, a positive integer, how many positive integers less than n are relatively prime ...

  8. Android 性能优化(13)网络优化( 9)Determining and Monitoring the Docking State and Type

    Determining and Monitoring the Docking State and Type PreviousNext This lesson teaches you to Determ ...

  9. 理解 Java 构造函数不可以继承

    参考来源:http://www.52bowen.com/a/2604620.html

  10. C#手机充值系统开发(基于聚合数据)

    说是手机充值系统有点装了,其实就是调用了聚合数据的支付接口,其实挺简单的事 但是我发现博客园竟然没有类似文章,我就个出头鸟把我的代码贡献出来吧 首先说准备工作: 去聚合数据申请账号-添加手机支付的认证 ...