ac自动机模板及感悟

ac自动机模板感悟

今天第一次打出来了ac自动机这个模板。其一直被称为树上的kmp,但我觉得这句话很容易误导人,还是有些许不同。

首先给一篇csdn上的讲解ac自动机

构造fail数组

他的核心是构造fail数组(即kmp中的nxt),用bfs的方法,先让第一层的所有结点fail只想root,同时将其入队列。入队列后的操作较为麻烦,文字描述比较苍白,我上图和代码。

在这里插入图片描述

void getfail()
{
	queue<int> q;
	for(int i=0;i<26;i++)
		if(ch[0][i])
			fail[ch[0][i]]=0,
			q.push(ch[0][i]);	
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int i=0;i<26;i++)
		{
			if(ch[u][i])
				fail[ch[u][i]]=ch[fail[u]][i],
				q.push(ch[u][i]);
			else
				ch[u][i]=ch[fail[u]][i];
		}
	}		
}

处理询问

还有一个要注意的地方是询问时,要把走过的地方标为-1,确保不会再走(这个好像是一个剪枝的优化)

int ans=0,x=0;
	for(int i=0;i<txt.size();i++)
	{
		int c=txt[i]-'a';
		x=ch[x][c];
		for(int j=x;j&&num[j]!=-1;j=fail[j])
		{
			ans+=num[j];
			num[j]=-1;
		}
	}

最后有一个小地方,就是在这道题里,string比char数组快(卡了笔者两个小时,佛了)orz

全部代码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 10000000

int n,ch[MAXN][30],fail[MAXN],tot;
string s,txt;
int num[MAXN];
void insert(string s)
{
	int len=s.size(),x=0;
	for(int i=0;i<len;i++)
	{
		int c=s[i]-'a';
		if(!ch[x][c]) ch[x][c]=++tot;
		x=ch[x][c];
	}
	num[x]++;
}
void getfail()
{
	queue<int> q;
	for(int i=0;i<26;i++)
		if(ch[0][i])
			fail[ch[0][i]]=0,
			q.push(ch[0][i]);
	
	while(!q.empty())
	{
		int u=q.front();q.pop();
		for(int i=0;i<26;i++)
		{
			if(ch[u][i])
				fail[ch[u][i]]=ch[fail[u]][i],
				q.push(ch[u][i]);
			else
				ch[u][i]=ch[fail[u]][i];
		}
	}
		
}
int main()
{
//	freopen("r","2.in",stdin);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>s;
		insert(s);
	}
	getfail();
	cin>>txt;
	
	int ans=0,x=0;
	for(int i=0;i<txt.size();i++)
	{
		int c=txt[i]-'a';
		x=ch[x][c];
		for(int j=x;j&&num[j]!=-1;j=fail[j])
		{
			ans+=num[j];
			num[j]=-1;
		}
	}
	
	cout<<ans;
	
} 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值