小结:ac自动机
复杂度:
查找O(n),维护O(n)
概要:
应用了kmp的自匹配思想,在trie建图时维护一个fali指针,指向上一个匹配的点,这点是用bfs做到。匹配串的时候同样没匹配到就和kmp一样返回。
应用:单串匹配多模板,维护多模板里边的信息。
技巧及注意:
插入和trie一样,然后是bfs。
在bfs的过程中,注意以根开头的不需要匹配fail,即ch[0][i]不需要匹配他们的fail,即为空。
然后在查找的时候当找到一个时我们要遍历这个节点的整个fail树,然后取出信息后记得将信息清空。
一定要注意!节点数是不超过n个串的总长度!!!一定要切记!!!
注意!!bfs的时候一定要维护信息!!!!
例题:
- 【BZOJ】1030: [JSOI2007]文本生成器(递推+ac自动机)(将自动机的节点作为转移的状态然后递推)
- #include <cstdio>
- #include <cstring>
- #include <cmath>
- #include <string>
- #include <iostream>
- #include <algorithm>
- #include <queue>
- using namespace std;
- #define rep(i, n) for(int i=0; i<(n); ++i)
- #define for1(i,a,n) for(int i=(a);i<=(n);++i)
- #define for2(i,a,n) for(int i=(a);i<(n);++i)
- #define for3(i,a,n) for(int i=(a);i>=(n);--i)
- #define for4(i,a,n) for(int i=(a);i>(n);--i)
- #define CC(i,a) memset(i,a,sizeof(i))
- #define read(a) a=getint()
- #define print(a) printf("%d", a)
- #define dbg(x) cout << #x << " = " << x << endl
- #define printarr(a, n, m) rep(aaa, n) { rep(bbb, m) cout << a[aaa][bbb]; cout << endl; }
- inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<'0'||c>'9'; c=getchar()) if(c=='-') k=-1; for(; c>='0'&&c<='9'; c=getchar()) r=r*10+c-'0'; return k*r; }
- inline const int max(const int &a, const int &b) { return a>b?a:b; }
- inline const int min(const int &a, const int &b) { return a<b?a:b; }
- using namespace std;
- const int N=10000000, Type=26;
- int T[N][Type], w[N], fail[N], cnt, q[N], front, tail, ans;
- char str[1000000], st[1000000];
- inline void ins(char s[]) {
- int len=strlen(s), now=0;
- rep(i, len) {
- int t=s[i]-'a';
- if(!T[now][t]) T[now][t]=++cnt;
- now=T[now][t];
- }
- ++w[now];
- }
- void bfs() {
- int now=0;
- q[tail++]=0;
- while(tail!=front) {
- now=q[front++]; if(front==N) front=0;
- rep(i, 26) if(T[now][i]) {
- q[tail++]=T[now][i]; if(tail==N) tail=0;
- if(now==0) continue;
- int p=fail[now];
- while(p && !T[p][i]) p=fail[p];
- fail[T[now][i]]=T[p][i];
- }
- }
- }
- void ac(char s[]) {
- int len=strlen(s), now=0;
- rep(i, len) {
- int t=s[i]-'a';
- while(now && !T[now][t]) now=fail[now];
- now=T[now][t];
- t=now;
- while(t) {
- ans+=w[t];
- w[t]=0;
- t=fail[t];
- }
- }
- }
- int main() {
- scanf("%s", str);
- int n=getint();
- while(n--) {
- scanf("%s", st);
- ins(st);
- }
- bfs();
- ac(str);
- print(ans);
- return 0;
- }
没错,就是AC自动机!(可惜不像金坷垃那样~)
不多说,放上模板,不难理解的。
- #include <cstdio>
- #include <cstring>
- #include <queue>
- #define for1(i,a,n) for(i=a;i<=n;++i)
- #define for2(i,a,n) for(i=a;i<n;++i)
- #define for3(i,a,n) for(i=n;i>=a;--i)
- #define for4(i,a,n) for(i=n;i>a;--i)
- #define CC(i,a) memset(i, a, sizeof(i))
- using namespace std;
- const int N=10000000, Type=26;
- char a[N], b[N];
- int ch[N][Type], fail[N], w[N], ans, cnt=1;
- queue<int> q;
- void ins(char* s) {
- int u=0, v, i, len=strlen(s);
- for2(i, 0, len) {
- v=s[i]-'a';
- if(!ch[u][v]) ch[u][v]=cnt++;
- u=ch[u][v];
- }
- w[u]++;
- }
- void bfs() {
- fail[0]=0;
- q.push(0);
- int u, p, i;
- while(!q.empty()) {
- u=q.front(); q.pop();
- for2(i, 0, Type) if(ch[u][i]) {
- q.push(ch[u][i]); //先插入,后判断
- if(!u) continue; //不要在这里错了。。
- p=fail[u];
- while(p && !ch[p][i]) p=fail[p];
- fail[ch[u][i]]=ch[p][i];
- }
- }
- }
- void ac(char* s) {
- int i, u=0, v, len=strlen(s), t;
- for2(i, 0, len) {
- v=s[i]-'a';
- while(u && !ch[u][v]) u=fail[u];
- u=ch[u][v];
- t=u;
- while(t) {
- ans+=w[t];
- w[t]=0;
- t=fail[t];
- }
- }
- }
- void init() {
- CC(fail, 0);
- CC(ch, 0);
- CC(w, 0);
- }
- int main() {
- init();
- scanf("%s", a);
- int n, i;
- scanf("%d", &n);
- for1(i, 1, n) {
- scanf("%s", b);
- ins(b);
- }
- bfs();
- ac(a);
- printf("%d\n", ans);
- return 0;
- }
注意一些细节即可
小结:ac自动机的更多相关文章
- AC自动机学习小结
AC自动机 简要说明 \(AC\) 自动机,全称 \(Aho-Corasick\ automaton\) ,是一种有限状态自动机,应用于多模式串匹配.在 \(OI\) 中通常搭配 \(dp\) 食用. ...
- AC自动机详解 (P3808 模板)
AC自动机笔记 0.0 前言 哇,好久之前就看了 KMP 和 Trie 树,但是似乎一直没看懂 AC自动机?? 今天灵光一闪,加上之前看到一些博客和视频,瞬间秒懂啊... 其实这个玩意还是蛮好理解的. ...
- AC自动机fail树小结
建议大家学过AC自动机之后再来看这篇小结 fail树就是讲fail指针看做一条边连成的树形结构 fail指针在AC自动机中的含义是指以x为结尾的后缀在其他模式串中所能匹配的最长前缀的长度 所以在模式串 ...
- 【原创】AC自动机小结
有了KMP和Trie的基础,就可以学习神奇的AC自动机了.AC自动机其实就是在Trie树上实现KMP,可以完成多模式串的匹配. AC自动机 其实 就是创建了一个状态的转移图,思想很 ...
- AC自动机小结
专题链接 第一题--hdu2222 Keywords Search ac自动机的模板题,入门题. 题解 第二题--hdu2896 病毒侵袭 一类病毒的入门题,类似模板 题解 第三题--hdu3 ...
- AC自动机算法小结
AC自动机,可惜不能自动AC 转载:飘过的小牛 OIer55242 简介 Aho-Corasick automation 该算法在1975年产生于贝尔实验室,是著名的多模匹配算法之一.一个常见的例子就 ...
- 【专题】字符串专题小结(AC自动机 + 后缀自动机)
AC自动机相关: $fail$树: $fail$树上以最长$border$关系形成父子关系,我们定一个节点对应的串为根到该节点的路径. 对于任意一个非根节点$x$,定$y = fa_{x}$,那$y$ ...
- AC自动机 & Fail树 专题练习
Fail树就是AC自动机建出来的Fail指针构成的树. [bzoj3172][xsy1713]单词 题意 给定一些单词,求每个单词在所有单词里面的出现次数. 分析 构建Fail树,记录每个单词最后一个 ...
- Aho-Corasick automaton(AC自动机)解析及其在算法竞赛中的典型应用举例
摘要: 本文主要讲述了AC自动机的基本思想和实现原理,如何构造AC自动机,着重讲解AC自动机在算法竞赛中的一些典型应用. 什么是AC自动机? 如何构造一个AC自动机? AC自动机在算法竞赛中的典型应用 ...
随机推荐
- Ubuntu上安装gtk2.0不能安装的问题,“下列的软件包有不能满足的依赖关系”
zez@localhoss:~$ sudo apt-get install libgtk2.0-dev正在读取软件包列表... 完成正在分析软件包的依赖关系树 正在读取状态信息... 完成 ...
- PYTHON实现HTTP基本认证(BASIC AUTHENTICATION)
参考: http://www.voidspace.org.uk/python/articles/authentication.shtml#id20 http://zh.wikipedia.org/wi ...
- XPath常用定位节点元素语句总结
将一个XML或HTML文档转换成了DOM树结构后,如何才能定位到特定的节点?XPath实现了这样的功能,它通过DOM树中节点的路径和属性来导航,通过XPath路径表达式可以选择DOM树中的nodes( ...
- cocos2dx3.0rc导出自定义类到lua的方法
以前要导出c++类到lua,就得手动维护pkg文件,那简直就是噩梦,3.0以后就会感觉生活很轻松了. 转载请注明出处http://www.cnblogs.com/mrblue/p/3637910.ht ...
- python 将pdf分页后插入至word中
所用技术 1. python编程基础 2. 使用pyPdf 3. 使用python操作word 4. 正则表达式的使用 5. windows的bat编程 下面是一个pyPdf库使用的示例: from ...
- August 5th, 2016, Week 32nd, Friday
Life is made up of small pleasures. 生活由各种细小的幸福构成. Don't expect too much. I am not qualified to get m ...
- 大端(big endian)和小端(little endian)
http://www.cnblogs.com/Romi/archive/2012/01/10/2318551.html 当前的存储器,多以byte为访问的最小单元,当一个逻辑上的地址必须分割为物理上的 ...
- C++实现大数据乘法
结构体定义与封装 struct bigdatacom { private : ]; ]; public : void init(const char *str1,const char *str2) { ...
- C++基础内容复习
下列语句定义了5个变量: int count; double sales_price,sum; std::string title; Sales_item bookItem; 每个定义都是以类型说明符 ...
- ASP.NET MVC 3 使用Model自定义验证的样式
1.修改jquery.validate.unobtrusive.js 将onError方法修改 //修改的部分 //////////////////////////////////////////// ...