AC自动机

AC 自动机可以看做是一个 trie 树与 KMP 结合的一个东西。其解决的问题是 KMP 的升级版:多模式串匹配。

P3808 AC 自动机(简单版)

正常的多模式串匹配,AC 自动机的入门题。

由于模式串不少,因此我们先考虑将所有模式串插入一个 trie 树里。
然后我们考虑像 KMP 一样对于 trie 上的每一个点所对应的根到这个点所对应的字符串的失配指针。
由于每一个节点的失配指针都要靠其父亲来求,因此我们直接在 trie 树上 bfs。根据定义不难发现显然有 \(fail_v=ch_{fail_u,s_v}\)。其中 \(v\) 是 tire 树上 \(u\) 的儿子。
需要注意的是,如果 \(u\) 没有某种字符 \(s\) 的儿子,我们将 \(ch_{u,s}\gets ch_{fail_u,s}\) 是等效的。这样做是为了保证可以从一些匹配串计算到另外一些匹配串上。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+7;
int n,ch[N][26],idcnt,cnt[N],fail[N];
void insert(string s){
	int len=s.length(),u=0;
	for(int i=0;i<len;i++){
		if(!ch[u][s[i]-'a']) ch[u][s[i]-'a']=++idcnt;
		u=ch[u][s[i]-'a'];
	}
	cnt[u]++;
}
void AC(){
	queue <int> q;
	fail[0]=0;int u=0;for(int i=0;i<26;i++) if(ch[u][i]) fail[ch[u][i]]=0,q.push(ch[u][i]);
	while(!q.empty()){
		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 query(string t){
	int u=0,len=t.length(),ans=0;
	for(int i=0;i<len;i++){
		u=ch[u][t[i]-'a'];int v=u;
		while(v&&cnt[v]!=-1){
			ans+=cnt[v];cnt[v]=-1;v=fail[v];
		}
	}
	return ans;
}
signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){string s;cin>>s;insert(s);}
	AC();string t;cin>>t;cout<<query(t);return 0; 
} 
posted @ 2025-04-23 12:55  all_for_god  阅读(12)  评论(0)    收藏  举报