hdoj 2896 病毒侵袭(AC自动机)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2896
思路分析:题目为模式匹配问题,对于一个给定的字符串,判断能匹配多少个模式;该问题需要静态建树,另外需要对AC自动机的模板加以修改,
对于每个匹配的模式的最后一个单词的fail指针指向root,即可实现一个字符串进行多次模式匹配;
代码如下:
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int KIND = 128; const int MAX_NODE = 300 * 500; const int MAX_M = 10000 + 100; char str[MAX_M]; int vir_match[MAX_M]; struct Trie { int root, count; int next[MAX_NODE][KIND], fail[MAX_NODE], end[MAX_NODE]; void Init() { count = 0; root = NewNode(); } int NewNode() { for (int i = 0; i < KIND; ++i) next[count][i] = -1; end[count] = -1; return count++; } void Insert(char *str, int id) { int i = 0, k = 0; int now = root; while (str[i]) { k = str[i]; if (next[now][k] == -1) next[now][k] = NewNode(); now = next[now][k]; ++i; } end[now] = id; } void BuildAutomaton() { queue<int> Q; fail[root] = -1; Q.push(root); while (!Q.empty()) { int now = Q.front(); int p = -1; Q.pop(); if (end[now] != -1) fail[now] = root; for (int i = 0; i < KIND; ++i) { if (next[now][i] != -1) { if (now == root) fail[next[now][i]] = root; else { p = fail[now]; while (p != -1) { if (next[p][i] != -1) { fail[next[now][i]] = next[p][i]; break; } p = fail[p]; } if (p == -1) fail[next[now][i]] = root; } Q.push(next[now][i]); } } } } int Match(char *str) { int i = 0, k = 0, vir_count = 0; int p = root; while (str[i]) { k = str[i]; while (next[p][k] == -1 && p != root) p = fail[p]; p = next[p][k]; p = (p == -1) ? root : p; if (end[p] != -1) { vir_match[vir_count++] = end[p]; p = fail[p]; } ++i; } return vir_count; } }; Trie root; int main() { int vir_num = 0, web_num = 0; int match_count = 0, web_matched = 0; while (scanf("%d\n", &vir_num) != EOF) { root.Init(); for (int i = 0; i < vir_num; ++i) { gets(str); root.Insert(str, i + 1); } web_matched = 0; match_count = 0; root.BuildAutomaton(); scanf("%d\n", &web_num); for (int i = 0; i < web_num; ++i) { int ans = 0; gets(str); ans = root.Match(str); sort(vir_match, vir_match + ans); if (ans) { web_matched++; printf("web %d: ", i + 1); for (int j = 0; j < ans - 1; ++j) printf("%d ", vir_match[j]); printf("%d\n", vir_match[ans - 1]); } } printf("total: %d\n", web_matched); } return 0; }