P2444 [POI2000]病毒
#include <bits/stdc++.h>
using namespace std;
const int maxn = ;
struct Aho_Corasock_Automaton {
struct node {
int fail; // 失配指针
int son[]; // 子节点的位置
bool danger; // 危险标记
}Trie[maxn];
int cnt = ; // Trie指针
void insert(char *s) {
int len = strlen(s);
int now = ; // Trie当前指针
for (int i = ; i < len; ++i) {
if (Trie[now].son[s[i]-''] == ) { // 如果没有这个子节点
Trie[now].son[s[i]-''] = ++cnt; // 构造该节点
}
now = Trie[now].son[s[i]-''];
}
Trie[now].danger = true;
}
void get_fail() { // 构造fail指针
queue<int> que;
for (int i = ; i < ; ++i) { // 先提前构造第二层
if (Trie[].son[i] != ) { // 如果存在该节点
Trie[Trie[].son[i]].fail = ; // fail指向root节点
que.push(Trie[].son[i]); // 加入队列
}
}
while (!que.empty()) { // bfs求fail指针
int u = que.front(); que.pop();
for (int i = ; i < ; ++i) {
if (Trie[Trie[u].fail].danger == true)
Trie[u].danger = true;
if (Trie[u].son[i] != ) { // 如果存在该子节点
// 子节点的fail指针指向当前节点的fail指针指向内容相同的子节点
Trie[Trie[u].son[i]].fail = Trie[Trie[u].fail].son[i];
que.push(Trie[u].son[i]); // 加入队列
}
else { // 如果不存在这个子节点
// 当前节点的该子节点指向当前节点的fail指针指向的止隔子节点
Trie[u].son[i] = Trie[Trie[u].fail].son[i];
}
}
}
}
}AC;
bool vis[maxn];
bool dfs(int u) {
if (vis[u] == true) return true;
vis[u] = true;
if (!AC.Trie[AC.Trie[u].son[]].danger) {
if (dfs(AC.Trie[u].son[])) {
return true;
}
}
if (!AC.Trie[AC.Trie[u].son[]].danger) {
if (dfs(AC.Trie[u].son[])) {
return true;
}
}
vis[u] = false;
return false;
}
char t[maxn];
int main() {
int n; scanf("%d",&n);
for (int i = ; i <= n; ++i) {
scanf("%s",t);
AC.insert(t);
}
AC.get_fail();
if (dfs() == true) puts("TAK"); // 从字典树的根结点开始找环
else puts("NIE");
return ;
}