【洛谷】3808 【模板】AC自动机(简单版)
来源:互联网 发布:淘宝短网址 编辑:程序博客网 时间:2024/06/09 22:23
题目传送门
终于看懂啦!终于学会了AC自动机啦!(Flag立起)写篇博客梳理一下自己的思路吧。
在文章的开头,必须先放上一些大佬的博客来压压场面:当然是orz ZZK大佬,神犇传送门
然而AC自动机的原理其实是比较好理解的,就是把Trie树和KMP的思想结合起来。这么说起来KMP就是单个字符串的AC自动机啊。(雾)
给出许多模式串,把这些字符串都加入到Trie树中,在每个字符串结尾的叶子节点上计数。
然后在所有模式串都加入Trie树中后开始建立next树,也就是对于所有的模式串做KMP。
首先把和根节点直接相连的节点加入队列中,然后用BFS的思想来确定每个节点的next:取当前的队头,然后枚举这个节点的所有儿子,设当前儿子的字母为ch,当前节点的next为k,取所有存在的儿子,若节点k的ch儿子不为空,则当前节点的儿子的next就等于节点k的ch儿子的编号,否则k=next[k],即保证节点k到根的路径是当前节点到根节点路径的后缀,重复上述操作,直到确定了当前节点的ch儿子。
不过上述求next树的方法过于暴力,可能会TLE,那么我们就会想到上述操作是否有可以优化的地方,答案当然是有的。
依然是去当前的队头,枚举这个节点的所有儿子,若这个儿子存在,那么这个儿子的next就等于节点k的ch儿子,否则这个儿子就等于节点k的ch儿子。
为什么这样的操作可以保证正确性呢?因为我们可以考虑节点k的ch儿子,如果节点k的ch儿子不存在,则把它变成了一个指针,指向它如果存在时匹配的节点。
这样搞了以后就非常方便,不需要每次再向上枚举,浪费时间。
最后就是查询,这题的查询就是求给定的字符串中包含了多少模式串,只要每次向上枚举,答案加上当前节点的计数,然后把当前节点标记为不可取即可。
附上AC代码:
#include <cstdio>#include <cstring>#include <queue>using namespace std;const int N=1000010;struct note{int nt,ed,lk[26];}AC[N];int n,size=0;char s[N];inline void insert(char *s){int len=strlen(s+1),now=0;for (int i=1; i<=len; ++i){if (!AC[now].lk[s[i]-'a']) AC[now].lk[s[i]-'a']=++size;now=AC[now].lk[s[i]-'a'];}++AC[now].ed;return;}inline void build(){queue <int> que;for (int i=0; i<26; ++i)if (AC[0].lk[i]) AC[AC[0].lk[i]].nt=0,que.push(AC[0].lk[i]);while (!que.empty()){int p=que.front();que.pop();for (int i=0; i<26; ++i)if (AC[p].lk[i]) AC[AC[p].lk[i]].nt=AC[AC[p].nt].lk[i],que.push(AC[p].lk[i]);else AC[p].lk[i]=AC[AC[p].nt].lk[i];}return;}inline int query(char *s){int len=strlen(s+1);int now=0,ans=0;for (int i=1; i<=len; ++i){now=AC[now].lk[s[i]-'a'];for (int j=now; j&&AC[j].ed!=-1; j=AC[j].nt)ans+=AC[j].ed,AC[j].ed=-1;}return ans;}int main(void){scanf("%d",&n);for (int i=1; i<=n; ++i) scanf("%s",s+1),insert(s);AC[0].nt=0;build();scanf("%s",s+1),printf("%d",query(s));return 0;}
- 【洛谷】3808 【模板】AC自动机(简单版)
- AC自动机模板(【洛谷3808】)
- AC 自动机(模板)
- (AC自动机)模板
- 【洛谷P3796】【模板】AC自动机(加强版)
- 【洛谷】3796 【模板】AC自动机(加强版)
- AC自动机模板(数组实现版)
- AC自动机简单版
- AC自动机模板【洛谷3796】
- hdu2896(AC自动机模板)
- AC自动机模板(hdu2222)
- ac自动机模板(hdu2222)
- ac自动机模板(hdu2222)
- AC自动机模板(【CJOJ1435】)
- 【洛谷P3808】【模版】AC自动机(简单版)
- 【AC自动机】AC自动机模板
- ac自动机(dp)<AC自动机模板> ---高精度处理
- AC自动机模板(c++版和java版)
- uBlock Origin中文使用手册,告诉你uBlock Origin怎么用!
- java 线程池详解(实例)
- ios中淘宝底部导航栏的制作
- 个人笔记。Java基础几个知识点说明
- leetcode
- 【洛谷】3808 【模板】AC自动机(简单版)
- Android gradle 中使用productFlavors
- Android程序员学WEB前端(1)-HTML(1)-标准结构常用标签-Sublime
- Java中File的常用操作及方法
- 最短路径问题(Floyd算法)
- 1007. 素数对猜想 (20)
- (三)Linux进程、fork、wait、exec函数
- QT。子窗口不析构
- oracle 行号