题目描述
二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例:
例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
任务:
请写一个程序:
1.在文本文件WIR.IN中读入病毒代码;
?2.判断是否存在一个无限长的安全代码;
?3.将结果输出到文件WIR.OUT中。
输入输出格式
输入格式:
在文本文件WIR.IN的第一行包括一个整数n (n≤2000)(n\le 2000)(n≤2000) ,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。
输出格式:
在文本文件WIR.OUT的第一行输出一个单词:
TAK——假如存在这样的代码;
NIE——如果不存在。
输入输出样例
输入样例#1:
3 01 11 00000
输出样例#1:
NIE
Solution:
本题AC自动机+dfs。
直接对n个串构建出AC自动机,在求fail时,顺带把会出现单词作为后缀的节点标记,直接用失配边的end值更新当前节点就好了,然后从根节点跑一遍dfs,每次都不走那些被标记的节点或者已经搜索过肯定无解的节点,那么只要搜到了环,就说明可行。
代码:
1 #include<bits/stdc++.h> 2 #define il inline 3 #define ll long long 4 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) 5 #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--) 6 using namespace std; 7 const int N=30005; 8 int trie[N][2],cnt,fail[N],n; 9 bool ed[N],vis[N],ct[N]; 10 char s[N]; 11 12 il void insert(char *s){ 13 int len=strlen(s),p=0,x; 14 For(i,0,len-1){ 15 x=s[i]-‘0‘; 16 if(!trie[p][x])trie[p][x]=++cnt; 17 p=trie[p][x]; 18 } 19 ed[p]=1; 20 } 21 22 il void bfs(){ 23 queue<int>q; 24 For(i,0,1) if(trie[0][i]) q.push(trie[0][i]); 25 while(!q.empty()){ 26 int u=q.front();q.pop(); 27 For(i,0,1){ 28 int &v=trie[u][i]; 29 if(v) fail[v]=trie[fail[u]][i],ed[v]|=ed[fail[v]],q.push(v); 30 else v=trie[fail[u]][i]; 31 } 32 } 33 } 34 35 il void dfs(int now){ 36 if(vis[now]) puts("TAK"),exit(0); 37 if(ct[now]||ed[now])return; 38 vis[now]=ct[now]=1; 39 dfs(trie[now][0]),dfs(trie[now][1]); 40 vis[now]=0; 41 } 42 43 il void init(){ 44 scanf("%d",&n); 45 For(i,1,n) scanf("%s",s),insert(s); 46 bfs(); 47 dfs(0); 48 puts("NIE"); 49 } 50 51 int main(){ 52 init(); 53 return 0; 54 }
原文地址:https://www.cnblogs.com/five20/p/9473479.html
时间: 2024-10-17 19:08:56