# AC自动机入门

KMP算法可以解决单个模式串比较的问题，如果模式串有多个，那么KMP算法的效率就不尽如人意了。

AC自动机和KMP算法的思想是相同的，就是跳过不必要的移动，直接到失配的位置所对应处。只是AC自动机是以trie（字典树）为基础的。

1.计算trie树中每个节点失配后直接指向的位置
2.主串匹配

void create_fail () {
int s, t, i ;
node *x ;
h->fail = NULL ; // h means root
Q[1] = h ;
for ( s = 1, t = 1 ; s <= t ; s ++ ) {
x = Q[s] ;
for ( i = 0 ; i < 30 ; i ++ ) {
if ( x->nxt[i] ) {
for ( p = x->fail ; p && !p->nxt[i] ; p = p->fail ) ;
x->nxt[i]->fail = p? p->nxt[i] : h ;
Q[++t] = x->nxt[i] ;
}
}
}
}

int Match() {
int i, j, ans = 0 ;
char c ;
q = h ;
for ( i = 1 ; i <= m ; i ++ ) {
c = pat[i] ;
while ( q && !q->nxt[ c-'a' ] ) q = q->fail ;
q = q? q->nxt[c-'a'] : h ;
for ( p = q ; p ; p = p->fail ) {
ans += p->tim ;
p->tim = 0 ;
}
}
return ans ;
}

#include <iostream>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std ;
const int maxn = 60 ;
char s[10010][maxn], pat[1000010] ;
struct node {
node* nxt[30] ;
node *fail, *fa ;
int tim ;
char ch ;
node() {
for ( int i = 0 ; i < 30 ; i ++ )
nxt[i] = NULL ;
ch = '\0' ;
tim = 0 ;
fa = fail = NULL ;
}
} *h, *p, *q ;

int n, m, tot, len[10010] ;

void create_trie ( int x ) {
p = h ;
int c ;
for ( int i = 1 ; i <= len[x] ; i ++ ) {
c = s[x][i]-'a' ;
if ( p->nxt[c] )
p = p->nxt[c] ;
else {
( p->nxt[c] = new node ) -> fa = p ;
p = p->nxt[c] ;
p->ch = s[x][i] ;
}
}
p->tim ++ ;
}

node *Q[100010] ;
void create_fail () {
int s, t, i ;
node *x ;
h->fail = NULL ;
Q[1] = h ;
for ( s = 1, t = 1 ; s <= t ; s ++ ) {
x = Q[s] ;
//printf ( "BFS Q[%d] : %c\n", s-1, x->ch ) ;
for ( i = 0 ; i < 30 ; i ++ ) {
if ( x->nxt[i] ) {
for ( p = x->fail ; p && !p->nxt[i] ; p = p->fail ) ;
x->nxt[i]->fail = p? p->nxt[i] : h ;
//      printf ( "push : %c\n", x->nxt[i]->ch ) ;
Q[++t] = x->nxt[i] ;
}
}
}
}

int Match() {
int i, j, ans = 0 ;
char c ;
q = h ;
for ( i = 1 ; i <= m ; i ++ ) {
c = pat[i] ;
while ( q && !q->nxt[ c-'a' ] ) q = q->fail ;
q = q? q->nxt[c-'a'] : h ;
for ( p = q ; p ; p = p->fail ) {
ans += p->tim ;
p->tim = 0 ;
}
}
return ans ;
}

void check ( node* now ) {
printf ( "%c fa:%c fail:%c tim:%d\n", now->ch, now->fa?now->fa->ch:'N', now->fail?now->fail->ch:'N', now->tim ) ;
for ( int i = 0 ; i < 30 ; i ++ )
if ( now->nxt[i] )
check(now->nxt[i]) ;
}

int main() {
int i, j, k, _ ;
scanf ( "%d", &_ ) ;
while ( _-- ) {
scanf ( "%d", &n ) ;
h = new node ;
q = h ;
for ( i = 1 ; i <= n ; i ++ ) {
scanf ( "%s", s[i]+1 ) ;
len[i] = strlen( s[i]+1 ) ;
}
for ( i = 1 ; i <= n ; i ++ )
create_trie(i) ;

create_fail() ;
scanf ( "%s", pat+1 ) ;
m = strlen(pat+1) ;
printf ( "%d\n", Match() ) ;
}
return 0 ;
}

• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120