P2444 [POI2000]病毒
1 #include <bits/stdc++.h>
2 using namespace std;
3 const int maxn = 35000;
4
5 struct Aho_Corasock_Automaton {
6 struct node {
7 int fail; // 失配指针
8 int son[2]; // 子节点的位置
9 bool danger; // 危险标记
10 }Trie[maxn];
11 int cnt = 0; // Trie指针
12 void insert(char *s) {
13 int len = strlen(s);
14 int now = 0; // Trie当前指针
15 for (int i = 0; i < len; ++i) {
16 if (Trie[now].son[s[i]-'0'] == 0) { // 如果没有这个子节点
17 Trie[now].son[s[i]-'0'] = ++cnt; // 构造该节点
18 }
19 now = Trie[now].son[s[i]-'0'];
20 }
21 Trie[now].danger = true;
22 }
23 void get_fail() { // 构造fail指针
24 queue<int> que;
25 for (int i = 0; i < 2; ++i) { // 先提前构造第二层
26 if (Trie[0].son[i] != 0) { // 如果存在该节点
27 Trie[Trie[0].son[i]].fail = 0; // fail指向root节点
28 que.push(Trie[0].son[i]); // 加入队列
29 }
30 }
31 while (!que.empty()) { // bfs求fail指针
32 int u = que.front(); que.pop();
33 for (int i = 0; i < 2; ++i) {
34 if (Trie[Trie[u].fail].danger == true)
35 Trie[u].danger = true;
36 if (Trie[u].son[i] != 0) { // 如果存在该子节点
37 // 子节点的fail指针指向当前节点的fail指针指向内容相同的子节点
38 Trie[Trie[u].son[i]].fail = Trie[Trie[u].fail].son[i];
39 que.push(Trie[u].son[i]); // 加入队列
40 }
41 else { // 如果不存在这个子节点
42 // 当前节点的该子节点指向当前节点的fail指针指向的止隔子节点
43 Trie[u].son[i] = Trie[Trie[u].fail].son[i];
44 }
45 }
46 }
47 }
48 }AC;
49 bool vis[maxn];
50 bool dfs(int u) {
51 if (vis[u] == true) return true;
52 vis[u] = true;
53 if (!AC.Trie[AC.Trie[u].son[0]].danger) {
54 if (dfs(AC.Trie[u].son[0])) {
55 return true;
56 }
57 }
58 if (!AC.Trie[AC.Trie[u].son[1]].danger) {
59 if (dfs(AC.Trie[u].son[1])) {
60 return true;
61 }
62 }
63 vis[u] = false;
64 return false;
65 }
66 char t[maxn];
67 int main() {
68 int n; scanf("%d",&n);
69 for (int i = 1; i <= n; ++i) {
70 scanf("%s",t);
71 AC.insert(t);
72 }
73 AC.get_fail();
74 if (dfs(0) == true) puts("TAK"); // 从字典树的根结点开始找环
75 else puts("NIE");
76 return 0;
77 }