/*
E. Вирусы
Комитет По Исследованию Бинарных Вирусов обнаружил, что некоторые последовательности единиц и нулей являются кодами вирусов. Комитет изолировал набор кодов вирусов. Последовательность из единиц и нулей называется безопасной, если никакой ее подотрезок (т.е. последовательность из соседних элементов) не является кодом вируса. Сейчас цель комитета состоит в том, чтобы установить, существует ли бесконечная безопасная последовательность из единиц и нулей.
Указание: используйте алгоритм Ахо-Корасик.
Формат ввода
Первая строка входного файла virus.in содержит одно целое число n, равное количеству всех вирусных кодов. Каждая из следующих n строк содержит непустое слово, составленное из символов 0 и 1 — код вируса. Суммарная длина всех слов не превосходит 30 000.
Формат вывода
Первая и единственная строка выходного файла должна содержать слово:
TAK — если бесконечная, безопасная последовательность из нулей и единиц сушествует;
NIE — в противном случае.
in
3
01
11
00000
out
NIE
in
3
011
11
0000
out
TAK
*/
#include <ctime>
#include <cstdio>
#include <iostream>
#include <vector>
#include <cstdlib>
#include <set>
#include <string>
#include <unistd.h>
using namespace std;
struct Vertex {
string value;
int suffixLink = 0;
int parent;
bool isTerminal = false;
vector<int> childrenId;
};
void createSuffixLinks(vector<Vertex> &tree, int id) {
string letter;
letter += tree[id].value;
int vertexToCheck = tree[tree[id].parent].suffixLink;
if (vertexToCheck == -1)
createSuffixLinks(tree, tree[id].parent);
while (vertexToCheck != 0) {
for (int child : tree[vertexToCheck].childrenId) {
if (tree[child].value == letter) {
tree[id].suffixLink = child;
return;
}
}
if (tree[vertexToCheck].suffixLink == -1)
createSuffixLinks(tree, vertexToCheck);
vertexToCheck = tree[vertexToCheck].suffixLink;
}
for (int child : tree[0].childrenId) {
if (tree[child].value == letter) {
tree[id].suffixLink = child;
return;
}
}
tree[id].suffixLink = 0;
//cout << id << ' ' << tree[id].value << ' ' << tree[id].suffixLink << '\n';
}
vector<Vertex> createTree(const vector<string> &lines) {
setbuf(stdout, nullptr);
for (string line : lines) {
cout << line << '\n';
}
cout << '\n';
vector<Vertex> tree;
tree.push_back({"", 0, -1, false});
int freeId = 1;
for (string line : lines) {
int parent = 0;
for (size_t i = 0; i < line.size(); ++i) {
string letter;
letter += line[i];
bool flag = true;
for (int id : tree[parent].childrenId) {
if (tree[id].value == letter) {
tree[id].isTerminal = (i == line.size() - 1);
parent = id;
flag = false;
break;
}
}
if (flag) {
tree.push_back({letter, -1, parent, i == line.size() - 1});
tree[parent].childrenId.push_back(freeId);
parent = freeId;
++freeId;
}
}
}
for (int id : tree[0].childrenId) {
tree[id].suffixLink = 0;
}
for (size_t i = 1; i < tree.size(); ++i) {
if (tree[i].suffixLink == -1) {
//cout << i << '\n';
createSuffixLinks(tree, i);
}
}
return tree;
}
int moveToLetter(const vector<Vertex> &tree, const Vertex &from, const string &letter) {
for (int child : from.childrenId) {
if (tree[child].value == letter) {
return child;
}
}
if (from.value.empty())
return 0;
return moveToLetter(tree, tree[from.suffixLink], letter);
}
bool checkCycle(const vector<Vertex> &tree, vector<int> visited, int v) {
if (tree[v].isTerminal) {
visited[v] = 2;
return false;
}
// cout << v << '\n';
visited[v] = 1;
vector<string> alphabet({"0", "1"});
for (string letter : alphabet) {
int to = moveToLetter(tree, tree[v], letter);
if (to == v)
return true;
if (!visited[to]) {
if (checkCycle(tree, visited, to))
return true;
} else if (visited[to] == 1) {
return true;
}
}
visited[v] = 2;
return false;
}
void stressTest(int seed) {
srand(seed);
vector<string> viruses;
for (int i = 0; i < 4; ++i) {
string virus;
for (int j = 0; j < 6
; ++j) {
virus += char('0' + rand() % 2);
}
viruses.push_back(virus);
}
setbuf(stdout, nullptr);
for (string line : viruses) {
cout << line << '\n';
}
cout << '\n';
vector<Vertex> tree = createTree(viruses);
for (int i = 0; i < tree.size(); ++i)
cout << i << ' ' << tree[i].value << ' ' << tree[i].suffixLink << '\n';
vector<int> visited(tree.size());
for (int v = 0; v < tree.size(); ++v) {
if (!visited[v]) {
if (checkCycle(tree, visited, v)) {
cout << "TAK\n";
return;
}
}
}
cout << "NIE\n";
}
int main() {
int virusesCount;
cin >> virusesCount;
vector<string> viruses;
for (int i = 0; i < virusesCount; ++i) {
string virus;
cin >> virus;
viruses.push_back(virus);
}
vector<Vertex> tree = createTree(viruses);
for (int i = 0; i < tree.size(); ++i)
cout << i << ' ' << tree[i].value << ' ' << tree[i].suffixLink << '\n';
vector<int> visited(tree.size());
for (int v = 0; v < tree.size(); ++v) {
if (!visited[v]) {
if (checkCycle(tree, visited, v)) {
cout << "TAK";
return 0;
}
}
}
cout << "NIE";
}