這是一個英文版的講的比較好的AC自動機資料。
http://www.cs.uku.fi/~kilpelai/BSA05/lectures/slides04.pdf
如果不愛看英文,可以看我整理的大致的翻譯,再加上點解釋說明啥的,建議中英兩個版本結合著看,畢竟我翻譯的裡面可能有些錯誤。
http://download.csdn.net/download/morgan_xww/4476863
可以預覽一下文檔中的:
我的模板:
class ACAutomaton{public: static const int MAX_N = 10000 * 50 + 5; //最大結點數:模式串個數 X 模式串最大長度 static const int CLD_NUM = 26; //從每個結點出發的最多邊數,字元集Σ的大小,一般是26個字母 int n; //trie樹當前結點總數 int id['z'+1]; //字母x對應的結點編號為id[x] int fail[MAX_N]; //fail指標 int tag[MAX_N]; //根據題目而不同 int trie[MAX_N][CLD_NUM]; //trie樹,也就是goto函數 void init() { for (int i = 0; i < CLD_NUM; i++) id['a'+i] = i; } void reset() { memset(trie[0], -1, sizeof(trie[0])); tag[0] = 0; n = 1; } //插入模式串s,構造單詞樹(keyword tree) void add(char *s) { int p = 0; while (*s) { int i = id[*s]; if ( -1 == trie[p][i] ) { memset(trie[n], -1, sizeof(trie[n])); tag[n] = 0; trie[p][i] = n++; } p = trie[p][i]; s++; } tag[p]++; //因題而異 } //構造AC自動機,用BFS來計算每個結點的fail指標,就是構造trie圖 void construct() { queue<int> Q; fail[0] = 0; for (int i = 0; i < CLD_NUM; i++) { if (-1 != trie[0][i]) { fail[trie[0][i]] = 0; //root下的第一層結點的fail指標都指向root Q.push(trie[0][i]); } else { trie[0][i] = 0; //這是階段一中的第2步 } } while ( !Q.empty() ) { int u = Q.front(); Q.pop(); for (int i = 0; i < CLD_NUM; i++) { int &v = trie[u][i]; if ( -1 != v ) { Q.push(v); fail[v] = trie[fail[u]][i]; tag[u] += tag[fail[u]]; //因題而異,某些題目中不需要這句話 } else { //當trie[u][i]==-1時,設定其為trie[fail[u]][i],就構造了trie圖 v = trie[fail[u]][i]; } } } } //因題而異 //在目標串t中匹配模式串 int solve(char *t) { int q = 0, ret = 0; while ( *t ) { q = trie[q][id[*t]]; int u = q; while ( u != 0 ) { ret += tag[u]; tag[u] = 0; u = fail[u]; } t++; } return ret; }} ac;