这题的字母范围为128.
要注意的是,匹配之后不能将val[tmp] = 0; 因为下一个例子还要使用。
#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 * StringLength const int MAX_NODE = 100010; //节点个数,一般字符形式的题26个 const int CHILD_NUM = 128; //特定题目需要 char test[10010]; class ACAutomaton { private: //每个节点的儿子,即当前节点的状态转移 int chd[MAX_NODE][CHILD_NUM]; //记录题目给的关键数据 int val[MAX_NODE]; //传说中的fail指针 int fail[MAX_NODE]; //队列,用于广度优先计算fail指针 int Q[MAX_NODE]; //字母对应的ID // int ID[128]; //已使用节点个数 int sz; public: //初始化,计算字母对应的儿子ID,如:'a'->0 ... 'z'->25 void Initialize() { fail[0] = 0; // for (int i = 0 ; i < CHILD_NUM ; i ++) { // ID[i+base] = i; // } } //重新建树需先Reset void 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]; int c = *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] = key; } //建立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) { int flag[501]; memset(flag , 0, sizeof(flag)); res[0] = 0; int n = strlen(test); int p = 0; for(int i = 0; i < n; i++) { //int next = ID[test[i]]; int next = test[i]; int tmp = p = chd[p][next]; while(val[tmp] != 0 && flag[val[tmp]] == 0) { res[0]++; res[res[0]] = val[tmp]; // val[tmp] = 0; flag[val[tmp]] = 1; tmp = fail[tmp]; if(res[0] >= 3) return 3; } } return res[0]; } }AC; int main() { AC.Initialize(); int n; while(scanf("%d", &n) != EOF) { AC.Reset(); char temp[201]; for(int i = 1; i <= n; i ++) { scanf("%s", temp); AC.Insert(temp, i); } AC.Construct(); int m; scanf("%d", &m); int sum = 0; for(int i = 1; i <= m; i++) { scanf("%s", test); int result[5]; int cnt = AC.Work(result); if(cnt > 0) { sum += 1; sort(result+1, result+cnt+1); printf("web %d:", i); for(int j = 1; j <= cnt; j++) printf(" %d", result[j]); printf("\n"); } } printf("total: %d\n", sum); } return 0; }