Trie树:

把若干个单词按前缀合并就得到一棵树,这棵树称为Trie树。Trie树是有根树,每条边表示一个字符,每个节点表示一个从根到当前节点的唯一路径上的字符依次连接得到的字符串。由于空串是任何串的前缀,因此根就表示“空串”这个串。如何区分单词节点和非单词节点呢?插入单词的时候对每个节点mark一下即可。

KMP算法思想:

能匹配就匹配,不能匹配就进行尽量小的平移来达到匹配。

有限自动机:

自动机是一个处理信息的机器,它的核心是状态和状态转移(和dp一样??),通过设计不同的状态和状态转移函数,来得到不同功能的自动机,因此自动机的应用非常广泛。

ac自动机

对字符串S构造一个这样的自动机:假设自动机扫描字符串T后处于状态w(w是一个整数,表示匹配长度),那么T的后w个字符是S的前缀,且w是满足这个性质的最大值。那么状态转移函数就可以这样定义:w + 字符c --> q,表示[Tc]的后q个字符是S的前缀,且这个q是满足这个性质的最大值。因此,状态转移矩阵很容易在O(m3Σ)的时间内求出来。

上述自动机慢在确定q需要花费O(m2)的时间,由kmp算法思想知道,如果S[w] == c,那么q = w + 1,否则w需要回退。那么我们利用kmp的回退数组(next数组),可以将复杂度降低到接近O(mΣ)。

同样,考虑多串的情形,则利用队列分层计算失配数组。这里会产生1个新的问题,假设当前匹配到了某个状态,这个状态表示的字符串为S,那么意味着不仅找到了S,而且找到了S的所有后缀,具体解决方法是给每个状态增加1个后缀链接,指向它的最大后缀单词,这样在找的时候要加速不少。

code(hdu2222,统计有多少模板串出现在了文本串里面):

#include <bits/stdc++.h>
using namespace std;
#define X first
#define Y second
#define pb(x) push_back(x)
#define mp(x, y) make_pair(x, y)
#define all(a) (a).begin(), (a).end()
#define mset(a, x) memset(a, x, sizeof(a))
#define mcpy(a, b) memcpy(a, b, sizeof(b))
#define cas() int T, cas = 0; cin >> T; while (T --)
template<typename T>bool umax(T&a, const T&b){return a<b?(a=b,true):false;}
template<typename T>bool umin(T&a, const T&b){return b<a?(a=b,true):false;}
typedef long long ll;
typedef pair<int, int> pii;
#ifndef ONLINE_JUDGE
#include "local.h"
#endif int ans; class ACAutomaton {
public:
void clear() {
memset(node, 0, sizeof(node));
sz = 1;
}
void insert(char P[]) {
int now = 0;
for (int i = 0; P[i]; i ++) {
int id = index(P[i]);
if (!node[now][id]) node[now][id] = sz ++;
now = node[now][id];
}
node[now].cnt ++;
node[now].final_state = true;
}
void build() {
queue<int> Q;
for (int i = 0; i < SZ; i ++) {
if (node[0][i]) {
Q.push(node[0][i]);
}
}
while (!Q.empty()) {
int ch = Q.front(); Q.pop();
for (int i = 0; i < SZ; i ++) {
int next = node[ch][i];
if (next) {
int now = node[ch].fail;
while (now && !node[now][i]) now = node[now].fail;
int buf = node[now][i];
node[next].last = node[next].fail = buf;
if (!node[buf].final_state) node[next].last = node[buf].last;
Q.push(next);
}
}
}
}
void work(char T[]) {
int now = 0;
for (int i = 0; T[i]; i ++) {
int id = index(T[i]);
while (now && !node[now][id]) now = node[now].fail;
now = node[now][id];
find(i, now);
}
}
private:
const static int N = 250007;
const static int SZ = 26;
struct Node {
int next[SZ], fail, last;
bool final_state;
int cnt;
int &operator[] (int p) { return next[p]; }
};
Node node[N];
int sz;
void find(int p, int now) {
if (now == 0) return;
if (node[now].final_state) process(p, now);
find(p, node[now].last);
}
int index(char ch) {
return ch - 'a';
}
void process(int p, int now) {
ans += node[now].cnt;
node[now].final_state = false;
}
};
ACAutomaton ac;
char s[100], t[1234567]; int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
//freopen("out.txt", "w", stdout);
#endif // ONLINE_JUDGE
int T, n;
cin >> T;
while (T --) {
cin >> n;
ac.clear();
for (int i = 0; i < n; i ++) {
scanf("%s", s);
ac.insert(s);
}
scanf("%s", t);
ac.build();
ans = 0;
ac.work(t);
cout << ans << endl;
}
return 0;
}

  

动手实现--AC自动机的更多相关文章

  1. AC自动机:BZOJ 2434 阿狸的打字机

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1834  Solved: 1053[Submit][Sta ...

  2. BZOJ 3881 [Coci2015]Divljak(AC自动机+树状数组)

    建立AC自动机然后,加入一个串之后考虑这个串的贡献.我们把这个串扔到AC自动机里面跑.最后对经过每一个点到的这个点在fail树的根的路径上的点有1的贡献.求链的并,我们把这些点按DFS序排序,然后把每 ...

  3. 基于trie树做一个ac自动机

    基于trie树做一个ac自动机 #!/usr/bin/python # -*- coding: utf-8 -*- class Node: def __init__(self): self.value ...

  4. AC自动机-算法详解

    What's Aho-Corasick automaton? 一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一. 简单的说,KMP用来在一篇文章中匹配一个模式串:但 ...

  5. python爬虫学习(11) —— 也写个AC自动机

    0. 写在前面 本文记录了一个AC自动机的诞生! 之前看过有人用C++写过AC自动机,也有用C#写的,还有一个用nodejs写的.. C# 逆袭--自制日刷千题的AC自动机攻克HDU OJ HDU 自 ...

  6. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2545  Solved: 1419[Submit][Sta ...

  7. BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]

    3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 3198  Solved: 1532[Submit][Status ...

  8. BZOJ 1212: [HNOI2004]L语言 [AC自动机 DP]

    1212: [HNOI2004]L语言 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1367  Solved: 598[Submit][Status ...

  9. [AC自动机]【学习笔记】

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

随机推荐

  1. First Training

    B B - Local Extrema CodeForces - 888A You are given an array a. Some element of this array ai is a l ...

  2. Crossing River POJ过河问题

    A group of N people wishes to go across a river with only one boat, which can at most carry two pers ...

  3. 5. git 过滤,让某文件夹里无法提交新添加的文件

    . gitignore  向此文件里添加文件路径就行了.如( web/core/ ) 此时git status将看不到添加的文件或文件夹了

  4. 2. Git-命令行-删除本地和远程分支

    命令行方式 Git Bash: 切换到要操作的项目文件夹 命令行 : $ cd <ProjectPath> 查看项目的分支们(包括本地和远程) 命令行 : $ git branch -a ...

  5. bluecms v1.6 sp1 代码审计学习

    前言 正式开始代码审计的学习,拓宽自己的知识面.代码审计学习的动力也是来自团队里的王叹之师傅,向王叹之师傅学习. 这里参考了一些前辈,师傅的复现经验和bluecms审计的心得 安装 install.p ...

  6. scheduler_default_filters 详解

    Filter scheduler 是 nova-scheduler 默认的调度器,调度过程分为两步:     通过过滤器(filter)选择满足条件的计算节点(运行 nova-compute) 通过权 ...

  7. 【山外笔记-数据库】Memcached详解教程

    本文打印版文档下载地址 [山外笔记-数据库]Memcached详解教程-打印版.pdf 一.Memcached数据库概述 1.Memcached简介 (1)Memcached是一个自由开源的,高性能, ...

  8. 关于go的入门书籍——go自学的序

    说实话,许世伟的<GO语言编程>,承载的心血是轻易可见的.但是我更喜欢那种工具书,就是简单说明他干嘛她干嘛,就能干嘛干嘛··· 比如读张晏关于<取代Apache的高性能Web服务器& ...

  9. Caused by: java.lang.NumberFormatException: For input string: " 60"

    原因 原原因:string转int 格式出错 解决:我的输入文件格式在根据“,”分割完之后多出了一个空格,我想要的是“60” 但是分割完之后是“ 60”所以导致格式转换不匹配.

  10. Hbase详细架构图解

    @ 目录 主要组件 数据模型 注意:Hbase是依赖zookeeper和hdfs的,需要启动zk和hdfs. 主要组件 Zookeeper: HBase 通过 Zookeeper 来做 Master ...