题目描述
二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例:
例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
任务:
请写一个程序:
1.在文本文件WIR.IN中读入病毒代码;
2.判断是否存在一个无限长的安全代码;
3.将结果输出到文件WIR.OUT中。
输入输出格式
输入格式:
在文本文件WIR.IN的第一行包括一个整数n(nle 2000)(n≤2000),表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。
输出格式:
在文本文件WIR.OUT的第一行输出一个单词:
TAK——假如存在这样的代码;
NIE——如果不存在。
输入输出样例
题意:
给n个模式串,问能不能找到一个无限长的文本串,使得模式串没有出现在文本串里。
思路:
看到题目没想法......看了题解
我们会发现正常的AC自动机都是在文本串中去匹配模式串,现在不要模式串出现,那么也就是说希望Trie中被标记为模式串结尾的节点不要出现。我们将这个称为危险标记。而想要无限长的文本串,其实也就是在匹配过程中能否找到这样一个环,使得环上的节点都是安全的。
首先我们还是先建立fail数组,需要注意的是,如果一个节点的fail指针指向的节点是危险的,那么他本身也是危险的。
因为一个节点x的fail指针指向的节点y表示的是以y作为结尾的前缀与以x为结尾的前缀的后缀匹配的最长部分,也就是说根节点到y一定是在根节点到x中出现过的。
然后dfs,用一个数组vis标记路径,一个数组f标记是否访问过。vis在dfs结束后要恢复,是用来判断当前路径是否形成环的。
1 #include <iostream> 2 #include <set> 3 #include <cmath> 4 #include <stdio.h> 5 #include <cstring> 6 #include <algorithm> 7 #include <vector> 8 #include <queue> 9 #include <map> 10 using namespace std; 11 typedef long long LL; 12 #define inf 0x7f7f7f7f 13 14 int n; 15 const int maxn = 60000005; 16 17 struct Tree{ 18 int fail;//失配指针 19 int vis[2];//子节点位置 20 int ed;//标记有几个单词以这个节点结尾 21 }AC[maxn]; 22 string s; 23 int tot = 0; 24 25 void build(string s) 26 { 27 int len = s.length(); 28 int now = 0;//字典树当前指针 29 for(int i = 0; i < len; i++){ 30 if(AC[now].vis[s[i] - '0'] == 0){ 31 AC[now].vis[s[i] - '0'] = ++tot; 32 } 33 now = AC[now].vis[s[i] - '0']; 34 } 35 AC[now].ed = 1; 36 } 37 38 void get_fail() 39 { 40 queue<int> que; 41 for(int i = 0; i < 2; i++){ 42 if(AC[0].vis[i] != 0){ 43 AC[AC[0].vis[i]].fail = 0; 44 que.push(AC[0].vis[i]); 45 } 46 } 47 while(!que.empty()){ 48 int u = que.front(); 49 que.pop(); 50 for(int i = 0; i < 2; i++){ 51 if(AC[u].vis[i] != 0){ 52 AC[AC[u].vis[i]].fail = AC[AC[u].fail].vis[i]; 53 if(AC[AC[u].fail].ed){ 54 AC[u].ed = 1; 55 } 56 que.push(AC[u].vis[i]); 57 } 58 else{ 59 AC[u].vis[i] = AC[AC[u].fail].vis[i]; 60 } 61 } 62 } 63 } 64 65 bool vis[maxn], f[maxn]; 66 void dfs(int rt) 67 { 68 vis[rt] = true; 69 for(int i = 0; i < 2; i++){ 70 if(vis[AC[rt].vis[i]]){ 71 printf("TAK "); 72 exit(0); 73 } 74 else if(!AC[AC[rt].vis[i]].ed && !f[AC[rt].vis[i]]){ 75 f[AC[rt].vis[i]] = true; 76 dfs(AC[rt].vis[i]); 77 } 78 } 79 vis[rt] = false; 80 } 81 82 int main() 83 { 84 scanf("%d", &n); 85 for(int i = 0; i < n; i++){ 86 cin>>s; 87 build(s); 88 } 89 AC[0].fail = 0; 90 get_fail(); 91 dfs(0); 92 printf("NIE "); 93 //cout<<s[maxid]<<endl; 94 //cout<<AC_query(s)<<endl; 95 return 0; 96 }