「学习笔记」AC自动机
Aho-Corasick automaton
updata on 8.3.2020:重画了前缀树的图。
虽然还是很丑,但是至少正确性有保证。
前言
我还不会KMP
AC自动机是个好东西,虽然只有少数情况下能够真正地达到它名字所描述的效果
这是一种多模式匹配算法,用于在文本串中搜索模式串
学习AC自动机,我个人认为只需要学会Trie树就行了,当然如果会KMP的话就更好,因为AC自动机可以简单理解为 Trie+KMP。
时间复杂度
总的时间复杂度约为 ,其中 n 为模式串个数, m 为模式串的最大长度, len为文本串长度。
构建Trie树: ; 设置fail指针: ; 模式匹配:
步骤
见【字典树笔记】。
一个点的fail指针,即失配指针,其指向的位置的深度是肯定小于该点的深度的,
所以第一层(此处指树根的下一层)的结点的失配指针显然只能指向树根。
对于其他的任意一个结点 i,若其父亲的失配指针指向的结点的某一子结点 j 与其值相等,则结点 i 的失配指针指向 j;若不存在这种情况,则结点 i 的失配指针指向根结点。
如下图(红线表示失配指针)

求得所有失配指针后的图如下

跳fail,并打上标记去重。
#include <bits/stdc++.h>
#define tag -0x3f3f3f
using namespace std;
const int maxn=1e6+5;
struct node {
int son[26] , fail;
} tree[maxn];
int cnt=1;
int flag[maxn];
queue<int> que;
namespace AC_automaton {
inline void insert(char *str) {
int u=1 , len=strlen(str);
for (register int i=0; i<len; i++) {
int v=(int)(str[i]-'a');
if (tree[u].son[v]==0) {
tree[u].son[v]=++cnt;
}
u=tree[u].son[v];
}
flag[u]++;
}
inline void get_fail() {
for (register int i=0; i<26; i++) {
tree[0].son[i]=1;
}
que.push(1); tree[1].fail=0;
while (!que.empty()) {
int u=que.front(); que.pop();
for (register int i=0; i<26; i++) {
int v=tree[u].son[i] , fail=tree[u].fail;
if (!v) {
tree[u].son[i]=tree[fail].son[i];
}
else {
tree[v].fail=tree[fail].son[i];
que.push(v);
}
}
}
}
inline int query(char *str) {
int u=1 , ans=0 , len=strlen(str);
for (register int i=0; i<len; i++) {
int v=(int)(str[i]-'a') , pos=tree[u].son[v];
while (pos>1 && flag[pos]!=tag) {
ans+=flag[pos];
flag[pos]=tag;
pos=tree[pos].fail;
}
u=tree[u].son[v];
}
return ans;
}
}
using namespace AC_automaton;
template <typename conv>
inline conv read(conv &x) {
char ch=getchar(); bool flag=0;
if (ch=='-') {
flag=1;
}
while (ch<'0' || ch>'9') {
ch=getchar();
}
for (x=0; ch>='0' && ch<='9'; ch=getchar()) {
x=(x<<1)+(x<<3)+ch-'0';
}
if (flag) {
x=-x;
}
}
template <typename conv>
inline conv write(conv x) {
if (x<0) {
putchar('-');
x=-x;
}
if (x>9) {
write(x/10);
}
putchar(x%10+'0');
}
int n;
char str[maxn];
int main() {
read(n);
for (register int i=1; i<=n; i++) {
scanf("%s" , str);
insert(str);
}
get_fail();
scanf("%s" , str);
write(query(str));
return 0;
}

浙公网安备 33010602011771号