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 自动机能够在 \(\ ...
随机推荐
- JavaScript 内存详解 & 分析指南
前言 JavaScript 诞生于 1995 年,最初被设计用于网页内的表单验证. 这些年来 JavaScript 成长飞速,生态圈日益壮大,成为了最受程序员欢迎的开发语言之一.并且现在的 JavaS ...
- python模块详解 | progressbar
参考官方文档:https://pypi.org/project/progressbar/#description progressbar 安装: pip install progressbar pro ...
- Xshell与Xftp免费下载安装及步骤
Xshell与Xftp免费下载安装及步骤 1.进入Xshell的官网:https://www.netsarang.com/zh/ 加粗样式 2.选择你需要的软件进行下载如:Xshell 3.选择家庭和 ...
- 【Java】一个简单的Java应用程序
简单记录,Java 核心技术卷I 基础知识(原书第10 版) 一个简单的Java应用程序"Hello, World!" Hello, World! Goodbye,World! 一 ...
- 【七天搞定Python】day01.Python环境配置、pip、IDE、注释、变量,数据类型、标识符/关键字、输出、输入
什么是Python? 动态解释型语言,1982年由荷兰人Guido von Rossum发明. 更多细节可以google,这里不做展开. Python解释器: CPython(官方版本C语言实现) I ...
- 阿里云 RTC QoS 屏幕共享弱网优化之若干编码器相关优化
屏幕共享是视频会议中使用频率最高的功能之一,但在实际场景中用户所处网络环境复杂,常遇到丢包或者拥塞的情况,所以如何优化弱网环境下的用户体验也成为了音视频通信中重要的一环.本文主要分享阿里云 RTC Q ...
- PHP设计模式之装饰器模式(Decorator)
PHP设计模式之装饰器模式(Decorator) 装饰器模式 装饰器模式允许我们给一个类添加新的功能,而不改变其原有的结构.这种类型的类属于结构类,它是作为现有的类的一个包装 装饰器模式的应用场景 当 ...
- WTM5.0发布,全面支持.net5
WTM5.0是WTM框架开源2年以来最大的一次升级,全面支持.net5,大幅重构了底层代码,针对广大用户提出的封装过度,不够灵活,性能不高等问题进行了彻底的修改. 这次升级使WTM继续保持开箱即用,高 ...
- Java自学笔记1206
字符串比较string1.equals(string2) 代码如下: 1 package Demo_1206; 2 3 import java.util.Scanner; 4 5 public cla ...
- Linux Ubuntu系统版本通过Crontab设置定时任务的执行
Linux Ubuntu系统版本通过Crontab设置定时任务的执行 本文由本人收集网络信息总结而来 特别鸣谢:https://linux.zone/2258 1 crontab 简单介绍以及语法使用 ...