AC自动机——看似KMP在跑,其实fail在跳
先存代码
AC自动机(简单版)
#include<bits/stdc++.h>
#define maxn 1000007
using namespace std;
int n,ans;
int tr[maxn][28],val[maxn],cnt,fail[maxn];
char mod[maxn],tx[maxn];
queue<int >q; void build(char *a){
int now=0;
for(int i=0;a[i];i++){
if(!tr[now][a[i]-'a']) tr[now][a[i]-'a']=++cnt;
now=tr[now][a[i]-'a'];
}
val[now]++;
}//建树 void AC(){
for(int i=0;i<26;i++) if(tr[0][i]) q.push(tr[0][i]);//26个字母跑
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;i++){
if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]);//调取指针
else tr[u][i]=tr[fail[u]][i];//建立“虚边”——指向失配指针的i边
//这里已经改变了trie图
}
}
} int query(char *t){
int ol=0,u=0;
for(int i=0;t[i];i++){
u=tr[u][t[i]-'a'];
for(int j=u;j&&val[j]!=-1;j=fail[j])
ol+=val[j],val[j]=-1;//fail跳(这样其实很慢)
}
return ol;
} int main(){
// freopen("cin.in","r",stdin);
// freopen("co.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%s",mod),build(mod);
AC();
scanf("%s",tx);ans=query(tx);
printf("%d\n",ans);
}
AC自动机(加强版)
#include<bits/stdc++.h>
#define maxn 1000007
using namespace std;
int T,n,ans;
char mod[maxn][100],tx[maxn]; namespace AC{
int tr[maxn][27],fail[maxn],tot;
int cnt,val[maxn],num[maxn];
void Init(){
memset(tr,0,sizeof(tr));
memset(num,0,sizeof(num));
memset(fail,0,sizeof fail);
memset(val,0,sizeof val);
cnt=ans=0;
}
void insert(char *s,int id){
int now=0;
for(int i=0;s[i];i++){
if(!tr[now][s[i]-'a']) tr[now][s[i]-'a']=++cnt;
now=tr[now][s[i]-'a'];
}
val[now]=id;//记录id,这个不怕覆盖
}
queue<int >q;
void build(){
for(int i=0;i<26;i++) if(tr[0][i]) q.push(tr[0][i]);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;i++)
if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]),cerr<<fail[tr[u][i]]<<endl;
else tr[u][i]=tr[fail[u]][i];
}
}
void query(char *t){
int u=0;
for(int i=0;t[i];i++){
u=tr[u][t[i]-'a'];
for(int j=u;j;j=fail[j])
if(val[j]) num[val[j]]++,ans=max(ans,num[val[j]]);
}//还是跳,不过记录的不一样而已
printf("%d\n",ans);
for(int i=1;i<=n;i++) if(ans==num[i]) printf("%s\n",mod[i]);
}
} int main(){
scanf("%d",&n);
while(n){
AC::Init();
for(int i=1;i<=n;i++) scanf("%s",mod[i]),AC::insert(mod[i],i);
AC::build();
scanf("%s",tx);
AC::query(tx);
scanf("%d",&n);
}
}
AC自动机(二次加强版)
#include<bits/stdc++.h>
#define maxn 2000007
using namespace std;
int n;
char mod[maxn],tx[maxn];
int fail[maxn],tr[maxn][27],val[maxn],num[maxn];
int id[maxn],cnt,in[maxn],to[maxn]; void insert(char *a,int idx){
int now=0;
for(int i=0;a[i];i++){
if(!tr[now][a[i]-'a']) tr[now][a[i]-'a']=++cnt;
now=tr[now][a[i]-'a'];
}
val[now]++;id[idx]=now;//记录
} queue<int >q; void build(){
for(int i=0;i<26;i++) if(tr[0][i]) q.push(tr[0][i]);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;i++){
if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]),in[fail[tr[u][i]]]++;
else tr[u][i]=tr[fail[u]][i];
}
}
} void query(char *t){
int u=0;
for(int i=0;t[i];i++)
u=tr[u][t[i]-'a'],num[u]++;
} void topu(){
for(int i=1;i<=cnt;i++) if(!in[i]) q.push(i);
while(!q.empty()){
int u=q.front(),v=fail[u];q.pop();
num[v]+=num[u];--in[v];
if(!(in[v])) q.push(v);
}
}//这里是跟题解学的topu,效率也挺高 int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%s",mod),insert(mod,i);
build();
scanf("%s",tx);query(tx);
topu();
for(int i=1;i<=n;i++) printf("%d\n",num[id[i]]);
}
单词
#include<bits/stdc++.h>
#define maxn 2000007
using namespace std;
int n;
char mod[maxn],tx[maxn],c[maxn];
int fail[maxn],tr[maxn][28],val[maxn],num[maxn];
int id[maxn],cnt,in[maxn],tot; void insert(char *a,int idx){
int now=0;
for(int i=0;a[i];i++){
if(!tr[now][a[i]-'a']) tr[now][a[i]-'a']=++cnt;
now=tr[now][a[i]-'a'];
}
val[now]++;id[idx]=now;
} queue<int >q; void build(){
for(int i=0;i<27;i++) if(tr[0][i]) q.push(tr[0][i]);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<27;i++){
if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]),in[fail[tr[u][i]]]++;
else tr[u][i]=tr[fail[u]][i];
}
}
} void query(char *t){
int u=0;
for(int i=0;t[i];i++)
u=tr[u][t[i]-'a'],num[u]++;
} void topu(){
for(int i=1;i<=cnt;i++) if(!in[i]) q.push(i);
while(!q.empty()){
int u=q.front(),v=fail[u];q.pop();
num[v]+=num[u];--in[v];
if(!(in[v])) q.push(v);
}
} void work(char *a,char *b){
int len1=strlen(a),len2=strlen(b);
for(int i=len1;i<len1+len2;i++)
a[i]=b[i-len1];
} int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%s",c),work(mod,c),
tot=strlen(mod),insert(c,i),mod[tot++]='{';
build();
query(mod);topu();
for(int i=1;i<=n;i++) printf("%d\n",num[id[i]]);
}
AC自动机——看似KMP在跑,其实fail在跳的更多相关文章
- AC自动机及KMP练习
好久都没敲过KMP和AC自动机了.以前只会敲个kuangbin牌板子套题.现在重新写了自己的板子加深了印象.并且刷了一些题来增加自己的理解. KMP网上教程很多,但我的建议还是先看AC自动机(Trie ...
- 2017多校第8场 HDU 6138 Fleet of the Eternal Throne AC自动机或者KMP
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6138 题意:给n个串,每次询问x号串和y号串的最长公共子串的长度,这个子串必须是n个串中某个串的前缀 ...
- AC自动机讲解
今天花了半天肝下AC自动机,总算啃下一块硬骨头,熬夜把博客赶出来.. 正如许多博客所说,AC自动机看似很难很妙,而事实上不难,但的确很妙.笼统地说,AC自动机=Trie+KMP,但是仅仅知道这个并没有 ...
- 初学AC自动机
前言 一直听说\(AC\)自动机是一个很难很难的算法,而且它不在\(NOIP\)提高组范围内(这才是关键),所以我一直没去学. 最近被一些字符串题坑得太惨,于是下定决心去学\(AC\)自动机. 简介 ...
- AC自动机简明教程
不会kmp和Trie树的请点击右上角X. AC自动机与kmp的唯一区别便是从单模式串变成了多模式串. 那么与kmp相同,AC自动机中的fail指针是指向当前状态的最长后缀. 当然这个后缀要在Trie树 ...
- AC自动机讲解超详细
begin:2019/5/2 感谢大家支持! AC自动机详细讲解 AC自动机真是个好东西!之前学KMP被Next指针搞晕了,所以咕了许久都不敢开AC自动机,近期学完之后,发现AC自动机并不是很难,特别 ...
- 【模版 Luogu P3808/P3796/P5357】AC自动机(简论)
浙江集训Day9,没有出任何实质性成果,只好把昨天打完的板子记一下. 该博客基于luogu的三道模版题.只有一个大致的讲解,主要提供代码给自己参考. ------------------------- ...
- 「笔记」AC 自动机
目录 写在前面 定义 引入 构造 暴力 字典图优化 匹配 在线 离线 复杂度 完整代码 例题 P3796 [模板]AC 自动机(加强版) P3808 [模板]AC 自动机(简单版) 「JSOI2007 ...
- AC 自动机学习笔记
虽然 NOIp 原地爆炸了,目前进入 AFO 状态,但感觉省选还是要冲一把,所以现在又来开始颓字符串辣 首先先复习一个很早很早就学过但忘记的算法--自动 AC AC自动机. AC 自动机能够在 \(\ ...
随机推荐
- Laya 小游戏通用框架设计理念
当前在用laya做小游戏开发,做了几个项目,总结了一下游戏中所需要的一些模块,大概理了一下,然后写成一套自己习惯使用的框架 总结了一下其中的模块 大概要分为一下模块 1.Base 模块 存放一些 ...
- LeetCode 二分查找模板 III
模板 #3: int binarySearch(vector<int>& nums, int target){ if (nums.size() == 0) return -1; i ...
- N叉树的最大深度-DFS
再看这道题之前,先来一道类似的简单题. 题目:求二叉树的最大深度 给定一个二叉树,找出其最大深度. 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数. 说明: 叶子节点是指没有子节点的节点. 示 ...
- 【Java集合】HashSet源码解析以及HashSet与HashMap的区别
HashSet 前言 HashSet是一个不可重复且元素无序的集合.内部使用HashMap实现. 我们可以从HashSet源码的类注释中获取到如下信息: 底层基于HashMap实现,所以迭代过程中不能 ...
- 解决Cannot find module '@angular/compiler-cli'
前言: 今天clone之前做的一个angular项目,使用ng serve一直提示An unhandled exception occurred: Cannot find module '@angul ...
- 容器编排系统K8s之Prometheus监控系统+Grafana部署
前文我们聊到了k8s的apiservice资源结合自定义apiserver扩展原生apiserver功能的相关话题,回顾请参考:https://www.cnblogs.com/qiuhom-1874/ ...
- 微信小程序request请求的封装
目录 1,前言 2,实现思路 3,实现过程 3.1,request的封装 3.2,api的封装 4,实际使用 1,前言 在开发微信小程序的过程中,避免不了和服务端请求数据,微信小程序给我们提供了wx. ...
- 【Linux】awk想打印制定列以后的所有列
今天偶然研究awk,有一个文件,文件内容是全篇的1 2 3 4 5 6 7 8 9 0 现在想打印除了第一列意外的所有列 文件内容: [root@localhost ~]# cat test.txt ...
- consul是什么?
consul概念: consul是用来做注册中心的 他和eureka是一样的 注册中心一般都是集群的形式存在保证高可用 consul像是一个nosql 存储着键值对 可以做存储consul是c/s架构 ...
- 配置Charles 设置手机代理并允许https请求
前言: 在h5开发调试时,为实现手机app访问localhost地址,可以使用ip地址的方式,但一般公司app出于安全考虑,会限制只能访问其自有域名.因此,使用charles代理的方式 步骤 用手机代 ...