HDU 2222 Keywords Search(AC自动机)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2222
题意:给你n个模式串,一个长为m的主串,问有多少个模式串在主串中出现了(模式串可能重复)
思路:AC自动机水题,先根据这n个模式串建立trie树,再构造fail指针,最后扫描主串即可。
code:
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 using namespace std; 5 const int KIND = 26; 6 7 struct node 8 { 9 int num; 10 node* fail; 11 node* next[KIND]; 12 node() 13 { 14 num = 0; 15 fail = NULL; 16 for (int i = 0; i < KIND; ++i) next[i] = NULL; 17 } 18 }; 19 node* root; 20 21 void Insert(char str[]) 22 { 23 node* temp = root; 24 int len = strlen(str); 25 for (int i = 0; i < len; ++i) 26 { 27 int curr = str[i] - 'a'; 28 if (temp->next[curr] == NULL) 29 temp->next[curr] = new node(); 30 temp = temp->next[curr]; 31 } 32 ++(temp->num); 33 } 34 35 void Build() 36 { 37 queue<node*> Q; 38 root->fail = root; 39 for (int i = 0; i < KIND; ++i) 40 { 41 if (root->next[i] == NULL) 42 root->next[i] = root; 43 else 44 { 45 root->next[i]->fail = root; 46 Q.push(root->next[i]); 47 } 48 } 49 while (!Q.empty()) 50 { 51 node* temp = Q.front(); 52 Q.pop(); 53 for (int i = 0; i < KIND; ++i) 54 { 55 if (temp->next[i] == NULL) 56 temp->next[i] = temp->fail->next[i]; 57 else 58 { 59 temp->next[i]->fail = temp->fail->next[i]; 60 Q.push(temp->next[i]); 61 } 62 } 63 } 64 } 65 66 int Query(char str[]) 67 { 68 int len = strlen(str); 69 node* temp = root; 70 int res = 0; 71 for (int i = 0; i < len; ++i) 72 { 73 int curr = str[i] - 'a'; 74 temp = temp->next[curr]; 75 node* x = temp; 76 while (x != root) 77 { 78 res += x->num; 79 x->num = 0; 80 x = x->fail; 81 } 82 } 83 return res; 84 } 85 86 char str[1000010]; 87 int main() 88 { 89 int nCase; 90 scanf("%d", &nCase); 91 while (nCase--) 92 { 93 int n; 94 scanf("%d", &n); 95 root = new node(); 96 for (int i = 0; i < n; ++i) 97 { 98 scanf("%s", str); 99 Insert(str); 100 } 101 Build(); 102 scanf("%s", str); 103 printf("%d\n", Query(str)); 104 } 105 return 0; 106 }
数组实现:
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 using namespace std; 5 const int KIND = 26; 6 const int MAXN = 500005; 7 const int MAXM = 1000005; 8 9 struct Trie 10 { 11 int next[MAXN][KIND], fail[MAXN], end[MAXN]; 12 int root, L; 13 14 int create() 15 { 16 for (int i = 0; i < KIND; ++i) 17 next[L][i] = -1; 18 end[L++] = 0; 19 return L - 1; 20 } 21 22 void init() 23 { 24 L = 0; 25 root = create(); 26 } 27 28 void insert(char str[]) 29 { 30 int now = root; 31 int len = strlen(str); 32 for (int i = 0; i < len; ++i) 33 { 34 int curr = str[i] - 'a'; 35 if (next[now][curr] == -1) 36 next[now][curr] = create(); 37 now = next[now][curr]; 38 } 39 ++end[now]; 40 } 41 42 void build() 43 { 44 queue<int>Q; 45 fail[root] = root; 46 for (int i = 0; i < KIND; ++i) 47 { 48 if (next[root][i] == -1) 49 next[root][i] = root; 50 else 51 { 52 fail[next[root][i]] = root; 53 Q.push(next[root][i]); 54 } 55 } 56 while (!Q.empty()) 57 { 58 int now = Q.front(); 59 Q.pop(); 60 for (int i = 0; i < KIND; ++i) 61 { 62 if (next[now][i] == -1) 63 next[now][i] = next[fail[now]][i]; 64 else 65 { 66 fail[next[now][i]] = next[fail[now]][i]; 67 Q.push(next[now][i]); 68 } 69 } 70 } 71 } 72 73 int query(char str[]) 74 { 75 int now = root; 76 int len = strlen(str); 77 int res = 0; 78 for (int i = 0; i < len; ++i) 79 { 80 int curr = str[i] - 'a'; 81 now = next[now][curr]; 82 int temp = now; 83 while (temp != root) 84 { 85 res += end[temp]; 86 end[temp] = 0; 87 temp = fail[temp]; 88 } 89 } 90 return res; 91 } 92 }; 93 94 Trie ac; 95 char str[MAXM]; 96 int main() 97 { 98 int nCase; 99 scanf("%d", &nCase); 100 while (nCase--) 101 { 102 int n; 103 scanf("%d", &n); 104 ac.init(); 105 for (int i = 0; i < n; ++i) 106 { 107 scanf("%s", str); 108 ac.insert(str); 109 } 110 ac.build(); 111 scanf("%s", str); 112 printf("%d\n", ac.query(str)); 113 } 114 return 0; 115 }