HDU 2222 AC自动机经典题目

来源:互联网 发布:华为云计算大会2016 编辑:程序博客网 时间:2024/06/05 16:04

应用模板,对模板有更深入的理解。

1.       当前结点的失败指针

等于
      父节点的失败指针指向的结点的的同个字母儿子结点的指针

 

2. v = chd[ fail[u] ][i];这句为了别的结点计算败者指针提供便利。无其他作用。

3. work在结点之间的转移方式

 

#include <cstdio>#include <cstdlib>#include <string>#include <climits>#include <iostream>#include <vector>#include <set>#include <cmath>#include <cctype>#include <algorithm>#include <sstream>#include <map>#include <cstring>#include <queue>using namespace std;//MAX_NODE = StringNumber * StringLengthconst int MAX_NODE = 500010;//节点个数,一般字符形式的题26个const int CHILD_NUM = 26;//特定题目需要char test[1000010];class ACAutomaton {private://每个节点的儿子,即当前节点的状态转移int chd[MAX_NODE][CHILD_NUM];//记录题目给的关键数据int val[MAX_NODE];//传说中的fail指针int fail[MAX_NODE];//队列,用于广度优先计算fail指针int Q[MAX_NODE];//字母对应的IDint ID[128];//已使用节点个数int sz;public://初始化,计算字母对应的儿子ID,如:'a'->0 ... 'z'->25void Initialize() {fail[0] = 0;for (int i = 0 ; i < CHILD_NUM ; i ++) {ID[i+'a'] = i;}}//重新建树需先Resetvoid Reset() {memset(chd[0] , 0 , sizeof(chd[0]));sz = 1;}//将权值为key的字符串a插入到trie中void Insert(char *a,int key) {int p = 0;for ( ; *a ; a ++) {int c = ID[*a];if (!chd[p][c]) {memset(chd[sz] , 0 , sizeof(chd[sz]));val[sz] = 0;chd[p][c] = sz ++;}p = chd[p][c];}val[p]++;}//建立AC自动机,确定每个节点的权值以及状态转移void Construct() {int *s = Q , *e = Q;for (int i = 0 ; i < CHILD_NUM ; i ++) {if (chd[0][i]) {fail[ chd[0][i] ] = 0;*e ++ = chd[0][i];}}while (s != e) { /*广度优先。 关键*/int u = *s++;for (int i = 0 ; i < CHILD_NUM ; i ++) {int &v = chd[u][i];if (v) {*e ++ = v; /*当前结点的失败指针 等于  父节点的失败指针指向的结点的的同个字母儿子结点的指针*/fail[v] = chd[ fail[u] ][i]; //以下一行代码要根据题目所给val的含义来写//val[v] |= val[ fail[v] ];} else {v = chd[ fail[u] ][i];}}}}//解题,特定题目需要int Work(){int res = 0;int n = strlen(test);int p = 0;for(int i = 0; i < n; i++){int next = ID[test[i]];int tmp = p = chd[p][next];while(val[tmp] != 0){res += val[tmp];val[tmp] = 0;tmp = fail[tmp];}} return res;}}AC;int main() {int t ;cin >> t ;AC.Initialize();while(t--){AC.Reset();int n;cin >> n;char temp[51];while(n--){scanf("%s", temp);AC.Insert(temp, 1);}AC.Construct();scanf("%s", test);printf("%d\n", AC.Work());}return 0;}