HDU 2222:Keywords Search(AC自动机模板)
http://acm.hdu.edu.cn/showproblem.php?pid=2222
KMP是单模式串匹配的算法,而AC自动机是用于多模式串匹配的算法。主要由Trie和KMP的思想构成。
题意:输入N个模式串,再给出一个文本串,求文本串里出现的模式串数目。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <cstdlib> 5 #include <algorithm> 6 #include <string> 7 #include <iostream> 8 #include <stack> 9 #include <map> 10 #include <queue> 11 using namespace std; 12 #define N 500001 13 /* 14 一个模式串的某个字符匹配失败的时候,就跳到它的失败指针上继续匹配,重复上述操作,直到这个字符匹配成功,所以失败指针一定满足一个性质,它指向的一定是某个串的前缀,并且这个前缀是当前结点所在前缀的后缀,而且一定是最长后缀。 15 */ 16 struct Ac_DFA 17 { 18 int next[N][26]; //一开始这里用了char结果MLE 19 int val[N], size, root, fail[N]; 20 21 int creat() { //构造新节点 22 for(int i = 0; i < 26; i++) { 23 next[size][i] = -1; 24 } 25 val[size] = 0; 26 return size++; 27 } 28 29 void init() { 30 size = 0; 31 root = creat(); 32 } 33 34 void insert(char s[]) { //插入模式串 35 int len = strlen(s); 36 int now = root; 37 for(int i = 0; i < len; i++) { 38 int c = s[i] - 'a'; 39 if(next[now][c] == -1) { 40 next[now][c] = creat(); 41 } 42 now = next[now][c]; 43 } 44 val[now]++; 45 } 46 47 void build() { //构造fail函数 48 queue<int> que; 49 while(!que.empty()) que.pop(); 50 for(int i = 0; i < 26; i++) { //初始化 51 if(next[root][i] == -1) { //如果没有边就补上去 52 next[root][i] = root; 53 } else { 54 fail[next[root][i]] = root; //有边的话第一个结点指向root 55 que.push(next[root][i]); 56 } 57 } 58 while(!que.empty()) { 59 int now = que.front(); que.pop(); 60 for(int i = 0; i < 26; i++) { 61 if(next[now][i] == -1) { 62 next[now][i] = next[fail[now]][i]; //如果没有边构造一条边出来 63 // 构造的边是fail指针指向的节点的出边 64 } else { 65 fail[next[now][i]] = next[fail[now]][i]; //有边fail就指向与目前的相同结点(以目前匹配的串的最长后缀为前缀)的一条边 66 que.push(next[now][i]); 67 } 68 } 69 } 70 } 71 72 int query(char s[]) { 73 int len = strlen(s); 74 int ans = 0; 75 int now = root; 76 for(int i = 0; i < len; i++) { 77 now = next[now][s[i] - 'a']; 78 int tmp = now; 79 while(tmp != root) { 80 ans += val[tmp]; 81 val[tmp] = 0; 82 tmp = fail[tmp]; // KMP思想:当前匹配失败,沿着失配边走看有没有能够匹配的串 83 } 84 } 85 return ans; 86 } 87 }; 88 89 char s[1000001]; 90 Ac_DFA ac; 91 92 int main() 93 { 94 int t; 95 scanf("%d", &t); 96 while(t--) { 97 int n; 98 scanf("%d", &n); 99 ac.init(); 100 for(int i = 0; i < n; i++) { 101 scanf("%s", s); 102 ac.insert(s); 103 } 104 ac.build(); 105 scanf("%s", s); 106 int ans = ac.query(s); 107 printf("%d\n", ans); 108 } 109 return 0; 110 }