首页 > 其他分享 >ac自动机(自习)

ac自动机(自习)

时间:2023-10-04 22:45:21浏览次数:34  
标签:ac tire int fail 3000005 自动机 自习

AC自动机自学笔记

目录

用途:

要学习之前肯定是要知道ac自动机是拿来干嘛的噻。

  1. 可以在一个字符串S中找到s1,s2,s3....的出现点以及出现次数。

定义:

AC,当然不是accepeted啦,而是某个名人(懒得记)研究出来的算法。
AC自动机作为一个机器需要两个东西支持,思想上叫做Kmp,行动上叫做tire

Tire字典树

这tire是处理多个模式串的基础
没学过?那你看什么ac自动机,回去巩固基础!
学过?那就不再赘述了。

Kmp算法:

同上,不再赘述

ac自动机

ac自动机其实相比于kmp而言就是在tire树上做cmp。
首先我们弄懂fail是什么意思,假如说我当前匹配到了bcd,但是d失配了,我可以通过fail建立一条边找到一个后缀为d的最长的东西来继续尝试匹配。
直到匹配成功或者只剩下这一个字母。特别地,只剩下一个时,他的fail边建向树根。
由于是在树上建立fail,我们找到一个节点时必须要知道其父节点是否出现过自己这个字符,所以要使用bfs来搞。

代码(基础版):

#include<bits/stdc++.h>
using namespace std;
int tree[3000005][30];
int val[3000005];
int fail[3000005];
int cnt=0;
void add(string s){
	int sz=s.size();
	int p=0;
	for(int i=0;i<sz;i++){
		int c=s[i]-'a';
		if(!tree[p][c]){
			tree[p][c]=++cnt;
		}
		p=tree[p][c]; 
	}
	val[p]++;
} 
void build(){
	queue<int>q; 
	for(int i=0;i<26;i++){
		if(tree[0][i]){
			q.push(tree[0][i]);
		}
	}
	while(q.size()){
		int u=q.front();
		q.pop();
		for(int i=0;i<26;i++){
			if(tree[u][i]){
				fail[tree[u][i]]=tree[fail[u]][i];
				q.push(tree[u][i]);
			}
			else{
				tree[u][i]=tree[fail[u]][i];
			}
		}
	}
}
int query(string s){
	int u=0;
	int ret=0;
	for(int i=0;i<s.size();i++){
		u=tree[u][s[i]-'a'];
		for(int j=u;j&&val[j]!=-1;j=fail[j]){
			ret+=val[j];
			val[j]=-1;
		}
	}
	return ret;
} 

int main(){
	int n;
	cin >>n;
	for(int i=1;i<=n;i++){
		string s;
		cin >>s;
		add(s);
	}
	build(); 
	string s;
	cin >>s;
	cout<<query(s);
}

代码记忆方式:

build有儿子ftui=tfui,没儿子tui=tfui。

加强版分析:

其实大体思路是一样的,不一样的是每一次跳fail的时候看看是不是跳到了一个叶子节点(也不一定就是,总之在建tire时标记一下),如果是,说明存在一个模版串,在相应位置val++
最后把所有val找最大值,然后每个地方记录一下父亲,往回跳就好了,时间复杂度不会太高,怕的话可以看看以后更新的对于ac自动机的优化

代码(加强版)

#include<bits/stdc++.h>
using namespace std;
int tree[3000005][30];
int fail[3000005];
int val[300005];
bool tail[300005];
int fa[300005];
char rev[300005];
int cnt;
void clear(){
	for(int i=0;i<=cnt;i++){
		for(int j=0;j<26;j++){
			tree[i][j]=0;
		}
		fail[i]=0;
		val[i]=0;
		tail[i]=0;
		fa[i]=0;
	}
	cnt=0;
}
void add(string s){
	int sz=s.size();
	int p=0;
	for(int i=0;i<sz;i++){
		int c=s[i]-'a';
		if(!tree[p][c]){
			tree[p][c]=++cnt;
			rev[cnt]=s[i];
			fa[cnt]=p;
		}
		p=tree[p][c]; 
	}
	tail[p]=1;
}
void build(){
	queue<int>q;
	for(int i=0;i<26;i++){
		if(tree[0][i]){
			q.push(tree[0][i]); 
		}
	}
	while(q.size()){
		int u=q.front();
		q.pop();
		for(int i=0;i<26;i++){
			if(tree[u][i]){
				fail[tree[u][i]]=tree[fail[u]][i];
				q.push(tree[u][i]); 
			}
			else{
				tree[u][i]=tree[fail[u]][i];
			} 
		}
	}
	
}
void query(string s){
	int sz=s.size();
	int u=0;
	int ret=0;
	for(int i=0;i<sz;i++){
		u=tree[u][s[i]-'a'];
		for(int j=u;j;j=fail[j]){
			if(tail[j]==1){
				val[j]++;
			}
		}
	}
}
void print(int pos){
	stack<char>q;
	while(pos){
		q.push(rev[pos]);
		pos=fa[pos];
	}
	while(q.size()){
		cout<<q.top();
		q.pop();
	}
	cout<<endl;
}
int main(){
	ios::sync_with_stdio(false);
	int n;
	while(cin >> n){
		if(n==0){
			return 0;
		}
		clear(); 
		for(int i=1;i<=n;i++ ){
			string s;
			cin >> s;
			add(s);
		}
		build();
		string s;
		cin >>s;
		query(s);
		int mx=0;
		for(int i=0;i<=cnt;i++){
			mx=max(mx,val[i]);
		}
		cout<<mx<<endl;
		for(int i=0;i<=cnt;i++){
			if(val[i]==mx){
				print(i);
			}
		}
	}
	
}

标签:ac,tire,int,fail,3000005,自动机,自习
From: https://www.cnblogs.com/linghusama/p/17742870.html

相关文章

  • P9019 [USACO23JAN] Tractor Paths P 题解
    Description有\(n\)个区间,第\(i\)个区间为\([l_i,r_i]\)。保证\(l_1<l_2<\cdots<l_n\)且\(r_1<r_2<\cdots<r_n\)。其中一部分区间是特殊的,输入会给定。如果第\(i\)个区间和第\(j\)个区间相交,那么\(i,j\)之间有一条边。保证\(1,n\)联通。给定\(Q\)组询问,每次......
  • 关于 Failed to bind properties under 'sky.alioss.access-key-id' to java.lang.Str
    问题描述废话不多说,上截图解决方案问题出现的原因:因为自己没有按照格式去运行程序,在yml中把他们得位置向前一个单位就解决问题了......
  • 利用不可识别的人脸来增强人脸识别性能Harnessing Unrecognizable Faces for Improvin
    灰色标记:可以日后引用的观点红色标记:好的写法、语句、单词紫色标记:文章重点黄色标记:寻常突出文章评论::创新点::主要内容::gallery中的样本通常是人为采集并精心挑选的,它们具有较好的可识别性;然而,query通常来自于真实场景,它们受多种因素干扰如像素等等。......
  • 工具 | 极其方便的谷歌翻译软件 Myna for Google Translate for Mac | Mac
    工具|极其方便的谷歌翻译软件MynaforGoogleTranslateforMac|Mac前言Mac哪款翻译软件好用呢?市面有太多的翻译工具了,如:百度、谷歌、有道等等。但是不得不说作为对外交流学习或学术阅览,谷歌翻译算得上是比较专业和让人信赖的。而MynaforGoogleTranslateforMac是......
  • 题解 accoders::NOI 5511【漂亮轰炸(bomb)】
    题解accoders::NOI5511【漂亮轰炸(bomb)】http://47.92.197.167:5283/contest/406/problem/4BZOJ3252是弱化版。problem一棵树,边带权。\(Q\)次询问,给定\(k\)和一个首都点,选择\(k\)条路径轰炸,其中必须由一轮要轰炸首都,但没有要求每条路径都经过首都。每条边只能被炸一次,......
  • 探索化学之秘:PerkinElmer ChemDraw Pro 2022 - 分子结构的视觉盛宴 mac+win版
    PerkinElmerChemDrawPro2022是一款全球领先的化学绘图软件,为全球科研人员、教育工作者以及工业界专业人士提供了直观、高效的工具,以创建、呈现和探索分子结构与化学反应。→→↓↓载PerkinElmerChemDrawPro2022mac/win版一、直观的绘图界面,快速构建分子模型PerkinElmer......
  • 服务器nf_conntrack(CT)表满导致虚拟机丢包
    现象虚拟机各种奇怪丢包(TCP的连接)然后看到虚拟机所在CVK的dmesg里,有如下:dmesgkern-lerr,warn-T(/var/log/messages里也有)提示:nf_conntrack:nf_conntrack:tablefull,droppingpacket从日志看意思是:内核netfilter模块conntrack相关参数配置不合理,导致新......
  • typscript: AbstractFactory
     /***file:factory.ts*抽象工厂*TheAbstractFactoryinterfacedeclaresasetofmethodsthatreturn*differentabstractproducts.Theseproductsarecalledafamilyandare*relatedbyahigh-levelthemeorconcept.Productsofonefamilyare......
  • access 使用Update更新记录时,提示"操作必须使用一个可更新的查询"
    原SQL:UPDATE刀具申购明细SET刀具申购明细.关闭=-1where刀具申购明细.申购数量<=(SELECTSum(Round(Nz([入库数量],0)*1,2))AS入库合计FROM采购入库tempLEFTJOIN刀具入库明细ON采购入库temp.申购ID=刀具入库明细.采购IDGROUPBY采购入库temp.申购ID)我本......
  • 各省数字专利申请数据计算(acl+permission功能的使用)
    需求:工作中需要计算各省数字专利申请数据,需要首先利用sql的acl参数对数据库的数据框进行预处理,然后通过permission参数进行转换后计算处理,最后利用分类分析法来进行单项计算和归类存储,用于后续的深度数据挖掘。解决:sql:DROPTABLEIFEXISTSacl;CREATETABLEacl(idintNOTN......