AC自动机学习笔记

这篇博客详细介绍了AC自动机(Aho-Corasick Algorithm)的基础知识和应用,包括KMP算法在AC自动机中的作用,以及如何构建失配指针。博主通过代码示例展示了AC自动机的构建过程,包括ins()函数用于插入字符串,get_fail()函数用于获取失配指针,以及fin()函数用于匹配字符串。博客强调了在处理多模式串匹配时AC自动机的效率,并提醒读者注意在处理多组数据时进行必要的清零和初始化操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天刚刚学习了AC自动机,刷了个模板题。

前置知识:trie树和KMP。
其实说实话吧,KMP在AC自动机里的运用其实就是失配指针。
失配指针其实就是在trie树上寻找最长的后缀,采用bfs的顺序是为了保证前后顺序的不变,当你在当前节点的时候知道你的上一层节点的失配指针的指向,在匹配中就可以节约大量时间来进行多模式串的匹配。
下附代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define N 510001
#define M 1100001
using namespace std;
int t,n,trie[N][26],tot=1,nxt[N],f[N],bo[N],ans;
char w[51],que[M];
void ins()
{
	int r=1,x,len=strlen(w+1);
	for(int i=1;i<=len;i++)
	{
		x=w[i]-'a';
		if(!trie[r][x]) trie[r][x]=++tot;
		r=trie[r][x];
	}
	bo[r]++;
	return;
}
void getfail()
{
	int q1=1,q2=1,r;
	f[1]=1,nxt[1]=0;
	for(int i=0;i<26;i++) trie[0][i]=1;
	for(;q1<=q2;++q1)
	{
		r=f[q1];
 		for(int i=0;i<26;i++)
		{
			if(!trie[r][i]) trie[r][i]=trie[nxt[r]][i];
			else
			{
				f[++q2]=trie[r][i];
				nxt[trie[r][i]]=trie[nxt[r]][i];
			}
		}
	}
	return;
}
void fin()
{
	int r=1,x,len=strlen(que+1),k;
	for(int i=1;i<=len;i++)
	{
		x=que[i]-'a',k=trie[r][x];
		while(k>1) ans+=bo[k],bo[k]=0,k=nxt[k];
		r=trie[r][x];
	}
	return;
}
int main()
{
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		scanf("%d",&n);
		for(int j=1;j<=n;j++) scanf("%s",w+1),ins();
		scanf("%s",que+1);
 		getfail(),fin();
		printf("%d\n",ans),ans=0;
		memset(bo,0,sizeof(bo));
		memset(trie,0,sizeof(trie));
	}
    return 0;	
} 

我们来看到getfail的函数部分,f是一个队列,用来存储下一层。如果当前节点没有失配指针的话,那么就指向默认的第一层(trie的根),如果有,那么加入队列,而且存储他的失配指针。
for(int i=0;i<26;i++) trie[0][i]=1;记住一定要初始化,否则节点会重复加入队列,造成死循环。
且AC自动机的题大多是多组数据,记得清零,初始化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值