[POI2000]病毒 - AC自动机
题目描述
二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例:
例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
任务:
请写一个程序:
1.在文本文件WIR.IN中读入病毒代码;
2.判断是否存在一个无限长的安全代码;
3.将结果输出到文件WIR.OUT中。
输入输出格式
输入格式:在文本文件WIR.IN的第一行包括一个整数n(n\le 2000)(n≤2000) ,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。
输出格式:在文本文件WIR.OUT的第一行输出一个单词:
TAK——假如存在这样的代码;
NIE——如果不存在。
输入输出样例
输出样例#1:
View Code
NIE
根据给出的病毒建出AC自动机,在上面DFS找环,单词的结尾的节点不能走,有环就代表有解。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <algorithm> 6 #define LL long long 7 8 using namespace std; 9 10 queue<int> q; 11 int len; 12 const int MAXN = 2e3 + 10; 13 char s[MAXN]; 14 int vis[MAXN], instack[MAXN]; 15 int flag = 0; 16 struct trie { 17 int fail; 18 int vis[2]; 19 int judge; 20 } t[MAXN * 10]; 21 22 inline LL read() 23 { 24 LL x = 0, w = 1; char ch = 0; 25 while(ch < '0' || ch > '9') { 26 if(ch == '-') { 27 w = -1; 28 } 29 ch = getchar(); 30 } 31 while(ch >= '0' && ch <= '9') { 32 x = x * 10 + ch - '0'; 33 ch = getchar(); 34 } 35 return x * w; 36 } 37 int tot = 0; 38 39 void insert() 40 { 41 int x = 0; 42 for(int i = 1; i <= len; i++) { 43 if(t[x].vis[s[i] - '0'] == 0) { 44 t[x].vis[s[i] - '0'] = ++tot; 45 } 46 x = t[x].vis[s[i] - '0']; 47 } 48 t[x].judge = 1; 49 } 50 51 void getfail() 52 { 53 for(int i = 0; i < 2; i++) { 54 if(t[0].vis[i]) { 55 t[t[0].vis[i]].fail = 0; 56 q.push(t[0].vis[i]); 57 } 58 } 59 while(!q.empty()) { 60 int x = q.front(); 61 q.pop(); 62 for(int i = 0; i < 2; i++) { 63 if(!t[x].vis[i]) { 64 t[x].vis[i] = t[t[x].fail].vis[i]; 65 } else { 66 t[t[x].vis[i]].fail = t[t[x].fail].vis[i]; 67 if(t[t[t[x].vis[i]].fail].judge == 1) { 68 t[t[x].vis[i]].judge = 1; 69 } 70 q.push(t[x].vis[i]); 71 } 72 } 73 } 74 } 75 76 void DFS(int x) 77 { 78 instack[x]++; 79 if(flag || t[x].judge == 1) { 80 return; 81 } 82 vis[x] = 1; 83 for(int i = 0; i < 2; i++) { 84 if(vis[t[x].vis[i]] == 1 && instack[t[x].vis[i]]) { 85 //cout<<t[x].vis[i]<<endl; 86 flag = 1; 87 return; 88 } 89 if(!vis[t[x].vis[i]]) { 90 DFS(t[x].vis[i]); 91 } 92 } 93 instack[x]--; 94 } 95 96 int main() 97 { 98 int n; 99 n = read(); 100 for(int i = 1; i <= n; i++) { 101 scanf("%s", s + 1); 102 len = strlen(s + 1); 103 insert(); 104 } 105 getfail(); 106 flag = 0; 107 DFS(0); 108 if(flag) { 109 cout<<"TAK"<<endl; 110 } else { 111 cout<<"NIE"<<endl; 112 } 113 } 114