【模板】AC自动机
点击查看代码
#include <stdio.h>
#include <queue>
#include <string.h>
enum {
the_size = 1000010
};
class AC_automaton {
private :
struct TRIE {
int fail;//fail指针;
int cnt;//此节点模式串数;
int sid[26];//子节点;
} trie[the_size];
int tot, ROOT;
std :: queue<int> q;
#define tr(id,choice) trie[id].sid[choice]
#define fail(id) trie[id].fail
#define cnt(id) trie[id].cnt
void AC_ins(char *pattern) {
int u = ROOT;
for(int i = 0;pattern[i];++i) {
if(!tr(u,pattern[i]-'a'))
tr(u,pattern[i]-'a') = ++tot;
u = tr(u,pattern[i]-'a');
}
cnt(u)++;
}
void AC_con() {
for(int i = 0;i < 26;++i)
if(tr(ROOT,i)) q.push(tr(ROOT,i));
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i = 0;i < 26;++i) {
if(tr(u,i)) {
fail(tr(u,i)) = tr(fail(u),i);
q.push(tr(u,i));
} else {
tr(u,i) = tr(fail(u),i);
}
}
}
}
int AC_qry(char *text) {
int u = 0, res = 0;
for(int i = 0;text[i];++i) {
u = tr(u,text[i]-'a');
for(int j = u;j&&cnt(j) != -1;j = fail(j)) {
res += cnt(j);
cnt(j) = -1;
}
}
return res;
}
#undef tr
#undef fail
#undef cnt
public :
void init() {
trie[tot].fail = trie[tot].cnt = 0;
memset(trie[tot].sid,0,sizeof(trie[tot].sid));
while(tot--) {
trie[tot].fail = trie[tot].cnt = 0;
memset(trie[tot].sid,0,sizeof(trie[tot].sid));
}
ROOT = 0;
}
void Insert(char *pattern) {
AC_ins(pattern);
}
void Construct() {
AC_con();
}
int Query(char *text) {
return AC_qry(text);
}
} automaton;
char tmp[the_size];
int n;
void automation() {
scanf("%d",&n);
for(int i = 1;i <= n;++i) {
scanf("%s",tmp);
automaton.Insert(tmp);
}
scanf("%s",tmp);
automaton.Construct();
printf("%d",automaton.Query(tmp));
return;
}
signed main() {
automation();
}
点击查看代码
#include <stdio.h>
#include <queue>
#include <string.h>
enum {
the_size = 16384
};
class AC_automaton {
private :
struct TRIE {
int fail;//fail指针;
int sid[26];//子节点;
int value, index;
} trie[the_size];
int tot, ROOT, cnt[the_size];
std :: queue<int> q;
#define tr(id,choice) trie[id].sid[choice]
#define fail(id) trie[id].fail
#define val(id) trie[id].value
#define ind(id) trie[id].index
void AC_ins(char *pattern,int index) {
int u = ROOT;
for(int i = 0;pattern[i];++i) {
if(!tr(u,pattern[i]-'a'))
tr(u,pattern[i]-'a') = ++tot;
u = tr(u,pattern[i]-'a');
}
ind(u) = index;
}
void AC_con() {
for(int i = 0;i < 26;++i)
if(tr(ROOT,i)) q.push(tr(ROOT,i));
while(!q.empty()) {
int u = q.front();
q.pop();
for(int i = 0;i < 26;++i) {
if(tr(u,i)) {
fail(tr(u,i)) = tr(fail(u),i);
q.push(tr(u,i));
} else {
tr(u,i) = tr(fail(u),i);
}
}
}
}
int AC_qry(char *text) {
int u = 0, res = 0;
for(int i = 0;text[i];++i) {
u = tr(u,text[i]-'a');
for(int j = u;j;j = fail(j))
val(j)++;
}
for(int i = 0;i <= tot;++i) {
if(ind(i)) {
res = std :: max(res,val(i));
cnt[ind(i)] = val(i);
}
}
return res;
}
#undef tr
#undef fail
#undef ind
#undef val
public :
void init() {
memset(cnt,0,sizeof(cnt));
trie[tot].fail = 0;
trie[tot].value = trie[tot].index = 0;
memset(trie[tot].sid,0,sizeof(trie[tot].sid));
while(tot--) {
trie[tot].fail = 0;
trie[tot].value = trie[tot].index = 0;
memset(trie[tot].sid,0,sizeof(trie[tot].sid));
}
//没想到这里错了,tot会减到-1;
tot = ROOT = 0;
}
void Insert(char *pattern,int index) {
AC_ins(pattern,index);
}
void Construct() {
AC_con();
}
int Query(char *text) {
return AC_qry(text);
}
int icnt(int i) {
return cnt[i];
}
void out() {
printf("%d :: \n",tot);
for(int i = 0;i <= tot;++i)
printf("%d %d %d\n",trie[i].fail,trie[i].index,trie[i].value);
}
} automaton;
char tmp[256][128];
char text[1000020];
int n;
void automation() {
while(scanf("%d",&n) != EOF) {
if(!n) break;
automaton.init();
for(int i = 1;i <= n;++i) {
scanf("%s",tmp[i]);
automaton.Insert(tmp[i],i);
}
automaton.Construct();
scanf("%s",text);
//automaton.out();
int ans = automaton.Query(text);
printf("%d\n",ans);
for(int i = 1;i <= n;++i)
if(automaton.icnt(i) == ans)
printf("%s\n",tmp[i]);
}
return;
}
signed main() {
automation();
}
二次加强
原理似乎是询问时,每个节点不再跳fail指针。
等到了最后一起沿着fail指针跳(拓扑序)。
其实因为我们在建fail指针的时候就是按着拓扑序跑的,所以不必再求一边拓扑序,把之前的队列循环一遍就好了。
单词 也用到了fail指针和拓扑序。
code
#include <stdio.h>
const int N = 2048576;
struct TRIE {
int sid[26];
int fail;
int cnt;
int flag;
} trie[N];
int trie_tot, top[N], ans[N];
#define edge(id,cid) trie[id].sid[cid]
#define fail(id) trie[id].fail
#define cnt(id) trie[id].cnt
#define flag(id) trie[id].flag
void insert(char *pattern,const int &val) {
int u = 0;
for(int i = 0;pattern[i];++i) {
pattern[i] -= 'a';
if(!edge(u,pattern[i]))
edge(u,pattern[i]) = ++trie_tot;
u = edge(u,pattern[i]);
}
if(!flag(u))
flag(u) = val;
top[val] = flag(u);
}
int q[N];
int head, tail;
void con() {
head = tail = 0;
for(int i = 25;~i;--i)
if(q[tail+1] = edge(0,i))
++tail;
while(head^tail) {
int u = q[++head], v;
for(int i = 25;~i;--i) {
if(v = edge(u,i)) {
q[++tail] = v;
fail(v) = edge(fail(u),i);
} else
edge(u,i) = edge(fail(u),i);
}
}
}
void query(const char *text) {
int u = 0;
for(int i = 0;text[i];++i) {
u = edge(u,text[i]-'a');
++cnt(u);
}
for(int i = trie_tot;~i;--i) {
ans[flag(q[i])] = cnt(q[i]);
cnt(fail(q[i])) += cnt(q[i]);
}
}
char tmp[N];
int n;
signed main() {
scanf("%d",&n);
for(int i = 1;i <= n;++i) {
scanf("%s",tmp);
insert(tmp,i);
}
con();
scanf("%s",tmp);
query(tmp);
for(int i = 1;i <= n;++i)
printf("%d\n",ans[top[i]]);
}