Tags:字符串
作业部落
\(Aho-Corasic\ automaton\),中文名\(AC\)自动机,是\(Trie\)图的一种,实现高效多串匹配单串的一种字符串算法
跟踪dalao的blog
\(Trie\)树上令一个点表示从根到它的串,那么一个点的fail
指向和它拥有最长后缀的串(所以可以指向\(0\))
[ ] [BZOJ2754]喵星球上的点名 https://www.luogu.org/problemnew/show/P2336
1
用来多串匹配单串或多串,效率高于\(KMP\)(可以代替),但是字符集很大时候需要大空间或用时间换空间(开\(set\))
2
套路:\(dp[i][j]\)表示到第\(i\)号节点(长串匹配到\(i\)),匹配长度为\(j\)(短串匹配到\(j\))的方案数啥的
!
\(Fail\)是一棵树,但是\(AC\)自动机是\(Trie\)图,可以存在环(病毒)
!
构造数据的时候,可以检查自己写的\(AC\)自动机是否可以从第一位开始匹配
洛谷3808模板1
首先建出\(Trie\)树(\(Build\)),然后通过\(BFS\)算出\(Fail\),再进行匹配
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=1000100;
struct Node{int ch[26],fail,end;}t[MAXN];
char s[MAXN];
int N,node;
queue<int> Q;
void Build()
{
int len=strlen(s),x=0;
for(int i=0;i<len;i++)
{
if(!t[x].ch[s[i]-'a']) t[x].ch[s[i]-'a']=++node;
x=t[x].ch[s[i]-'a'];
}
t[x].end++;
}
void Get_Fail()
{
for(int i=0;i<26;i++) if(t[0].ch[i]) Q.push(t[0].ch[i]);
while(!Q.empty())
{
int x=Q.front();Q.pop();
for(int i=0;i<26;i++)
if(t[x].ch[i])
{
t[t[x].ch[i]].fail=t[t[x].fail].ch[i];
Q.push(t[x].ch[i]);
}
else t[x].ch[i]=t[t[x].fail].ch[i];
}
}
int AC()
{
int len=strlen(s),x=0,ans=0;
for(int i=0;i<len;i++)
{
x=t[x].ch[s[i]-'a'];
for(int p=x;p&&~t[p].end;p=t[p].fail)
ans+=t[p].end,t[p].end=-1;
}
return ans;
}
int main()
{
cin>>N;while(N--){scanf("%s",s);Build();}
Get_Fail();scanf("%s",s);
printf("%d\n",AC());return 0;
}
原文:https://www.cnblogs.com/xzyxzy/p/9164771.html