hdoj 3065 病毒侵袭持续中(AC自动机)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3065
思路分析:问题需要模式匹配多个模式串,需要注意的是模式串会包含和重叠,需要对AC自动机的匹配过程进行修改,对于每个节点,需要从该节点的失败指针回溯,
如果失败指针回溯后的节点为某个模式串的最后一个节点,则匹配了另一个模式串;
代码如下:
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int KIND = 128; const int MAX_NODE = 1020 * 50; const int MAX_N = 1000 + 10; const int MAX_M = 2000000 + 100; char str[MAX_M]; int visited[MAX_N]; int vir_match[MAX_N]; char vir[MAX_N][60]; 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(); 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; int temp = p; while (temp != root) { if (end[temp] != -1) { if (visited[end[p]] == 0) vir_match[vir_count++] = end[p]; visited[end[p]]++; } temp = fail[temp]; } ++i; } return vir_count; } }; Trie root; int main() { int vir_num = 0; int match_count = 0; while (scanf("%d\n", &vir_num) != EOF) { root.Init(); memset(vir_match, 0, sizeof(vir_match)); memset(visited, 0, sizeof(visited)); for (int i = 0; i < vir_num; ++i) { gets(str); strcpy(vir[i], str); root.Insert(str, i + 1); } match_count = 0; root.BuildAutomaton(); gets(str); int ans = root.Match(str); sort(vir_match, vir_match + ans); if (ans) { for (int j = 0; j < ans - 1; ++j) printf("%s: %d\n", vir[vir_match[j] - 1], visited[vir_match[j]]); printf("%s: %d\n", vir[vir_match[ans - 1] - 1], visited[vir_match[ans - 1]]); } } return 0; }