HDU 3065 病毒侵袭持续中(AC自动机)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3065
题意:有n个模式串,一个主串,求每个模式串在主串中出现的次数
思路:AC自动机水题,trie树中也要维护标号,再开一个num数组记录出现次数即可,扫描匹配时注意跳转fail指针和root节点。
code:
1 #include <cstdio> 2 #include <cstring> 3 #include <string> 4 #include <queue> 5 using namespace std; 6 const int KIND = 26; 7 struct node 8 { 9 int id; 10 node* fail; 11 node* next[KIND]; 12 node () 13 { 14 id = 0; 15 fail = NULL; 16 for (int i = 0; i < KIND; ++i) next[i] = NULL; 17 } 18 }; 19 node* root; 20 int L; 21 char str[1005][55]; 22 char text[2000005]; 23 int num[1005]; 24 25 void Insert(char str[]) 26 { 27 node* temp = root; 28 int len = strlen(str); 29 for (int i = 0; i < len; ++i) 30 { 31 int curr = str[i] - 'A'; 32 if (temp->next[curr] == NULL) 33 temp->next[curr] = new node(); 34 temp = temp->next[curr]; 35 } 36 temp->id = ++L; 37 } 38 39 void Build() 40 { 41 queue<node*> Q; 42 root->fail = root; 43 for (int i = 0; i < KIND; ++i) 44 { 45 if (root->next[i] == NULL) 46 root->next[i] = root; 47 else 48 { 49 root->next[i]->fail = root; 50 Q.push(root->next[i]); 51 } 52 } 53 while (!Q.empty()) 54 { 55 node* temp = Q.front(); 56 Q.pop(); 57 for (int i = 0; i < KIND; ++i) 58 { 59 if (temp->next[i] == NULL) 60 temp->next[i] = temp->fail->next[i]; 61 else 62 { 63 temp->next[i]->fail = temp->fail->next[i]; 64 Q.push(temp->next[i]); 65 } 66 } 67 } 68 } 69 70 void Query() 71 { 72 node* temp = root; 73 int len = strlen(text); 74 for (int i = 0; i < len; ++i) 75 { 76 if (text[i] < 'A' || text[i] > 'Z') 77 { 78 temp = root; 79 continue; 80 } 81 int curr = text[i] - 'A'; 82 while (temp->next[curr] == NULL && temp != root) temp = temp->fail; 83 temp = temp->next[curr]; 84 if (temp == NULL) temp = root; 85 node* x = temp; 86 while (x != root) 87 { 88 if (x->id != 0) ++num[x->id]; 89 x = x->fail; 90 } 91 } 92 } 93 94 int main() 95 { 96 int n; 97 while (scanf("%d", &n) != EOF) 98 { 99 L = 0; 100 root = new node(); 101 for (int i = 1; i <= n; ++i) 102 { 103 scanf("%s", str[i]); 104 Insert(str[i]); 105 } 106 Build(); 107 scanf("%s", text); 108 memset(num, 0, sizeof(num)); 109 Query(); 110 for (int i = 1; i <= n; ++i) 111 { 112 if (num[i] == 0) continue; 113 printf("%s: %d\n", str[i], num[i]); 114 } 115 } 116 return 0; 117 }
数组实现:
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 using namespace std; 5 const int KIND = 26; 6 const int MAXN = 50005; 7 const int MAXM = 2000005; 8 9 struct Trie 10 { 11 int next[MAXN][KIND], fail[MAXN], id[MAXN], num[MAXN]; 12 int root, L, n; 13 int create() 14 { 15 for (int i = 0; i < KIND; ++i) 16 next[L][i] = -1; 17 id[L++] = 0; 18 return L - 1; 19 } 20 void init() 21 { 22 L = 0; 23 n = 0; 24 root = create(); 25 memset(num, 0, sizeof(num)); 26 } 27 void insert(char str[]) 28 { 29 int now = root; 30 int len = strlen(str); 31 for (int i = 0; i < len; ++i) 32 { 33 int curr = str[i] - 'A'; 34 if (-1 == next[now][curr]) 35 next[now][curr] = create(); 36 now = next[now][curr]; 37 } 38 id[now] = ++n; 39 } 40 void build() 41 { 42 queue<int>Q; 43 fail[root] = root; 44 for (int i = 0; i < KIND; ++i) 45 { 46 if (-1 == next[root][i]) 47 next[root][i] = root; 48 else 49 { 50 fail[next[root][i]] = root; 51 Q.push(next[root][i]); 52 } 53 } 54 while (!Q.empty()) 55 { 56 int now = Q.front(); 57 Q.pop(); 58 for (int i = 0; i < KIND; ++i) 59 { 60 if (-1 == next[now][i]) 61 next[now][i] = next[fail[now]][i]; 62 else 63 { 64 fail[next[now][i]] = next[fail[now]][i]; 65 Q.push(next[now][i]); 66 } 67 } 68 } 69 } 70 void query(char str[]) 71 { 72 int now = root; 73 int len = strlen(str); 74 for (int i = 0; i < len; ++i) 75 { 76 if (str[i] < 'A' || str[i] > 'Z') 77 { 78 now = root; 79 continue; 80 } 81 now = next[now][str[i] - 'A']; 82 int temp = now; 83 while (temp != root) 84 { 85 if (id[temp]) ++num[id[temp]]; 86 temp = fail[temp]; 87 } 88 } 89 } 90 }; 91 Trie ac; 92 char str[1005][55]; 93 char text[MAXM]; 94 int main() 95 { 96 int n; 97 while (scanf("%d", &n) != EOF) 98 { 99 ac.init(); 100 for (int i = 1; i <= n; ++i) 101 { 102 scanf("%s", str[i]); 103 ac.insert(str[i]); 104 } 105 ac.build(); 106 scanf("%s", text); 107 ac.query(text); 108 for (int i = 1; i <= n; ++i) 109 { 110 if (0 == ac.num[i]) continue; 111 printf("%s: %d\n", str[i], ac.num[i]); 112 } 113 } 114 return 0; 115 }