先上题:
题目描述
二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例:
例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
任务:
请写一个程序:
l 读入病毒代码;
2 判断是否存在一个无限长的安全代码;
3 将结果输出
输入
第一行包括一个整数n,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。
输出
你应在在文本文件WIN.OUT的第一行输出一个单词:
TAK——假如存在这样的代码;
NIE——如果不存在。
样例输入
3
01
11
00000
01
11
00000
样例输出
NIE
首先,别考虑直接输答案
![鄙视](http://static.blog.csdn.net/xheditor/xheditor_emot/default/despise.gif)
来说说思路:
trie树显然不行(关于trie树,就不多说了)。
So-用trie图。trie图可以使用后缀进行查找,让查找在图中畅通无阻。
重点是:如何判断可以出现无限长的代码呢?
想想,当图中出现
环且环中没有危险节点时,我们就按此环循环,可出现无限长代码。
使用拓扑排序可判断环(当前节点的入度都≥1时,有环。x的入度就是指向x节点的节点的个数)。
具体步骤:
1.创建trie树;
2.连接虚边,创建trie图;
3.进行搜索,消掉入度为零的点,减掉
入度为零的点指向的点的一个入度.
代码(请不要管注释,为调试信息-我的代码错了13次
):
![敲打](http://static.blog.csdn.net/xheditor/xheditor_emot/default/knock.gif)
#include<bits/stdc++.h>
using namespace std;
int n,trie[30001][2],nodenum=1,danger[30001],fail[30001],que[30001],head,tail,indeg[30001];
char s[30001];
int build_trie(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
int now=1;
for(int j=1;j<=strlen(s+1);j++){
if(danger[now]) break;
int t=s[j]-48;
if(trie[now][t]==0)
trie[now][t]=++nodenum;
now=trie[now][t];
}
danger[now]=1;
}
}
void build_acm(int root){
nodenum=1;
fail[root]=root;
head=1,tail=0;
for(int i=0;i<=1;i++){
if(trie[root][i]!=0){
fail[trie[root][i]]=root;
que[++tail]=trie[root][i];
indeg[trie[root][i]]++;
}
else trie[root][i]=root,indeg[1]++;
}
int u;
while(head<=tail){
u=que[head++];
if(danger[u]) continue;
nodenum++;
for(int i=0;i<=1;i++){
int v=trie[u][i];
if(v==0){
trie[u][i]=trie[fail[u]][i];
indeg[trie[u][i]]++;
continue;
}
fail[v]=trie[fail[u]][i];
que[++tail]=v;
danger[v]=danger[v]|danger[fail[v]];
indeg[trie[u][i]]++;
}
}
}
void toposort(){
if(indeg[1]>0){
printf("TAK");
return;
}
memset(que,0,sizeof(que));
int cnt=1;
head=1,tail=0;
que[++tail]=1;
// for(int i=1;i<=nodenum;i++) cout<<indeg[i]<<' '<<danger[i]<<endl;
// for(int i=1;i<=nodenum;i++) printf("node:%d,fail:%d,indeg:%d,lc:%d,rc:%d\n",i-1,fail[i]-1,indeg[i],trie[i][0]-1,trie[i][1]-1);
// cout<<endl;
while(head<=tail){
int num=que[head++];
for(int j=0;j<=1;j++){
if(danger[trie[num][j]]) continue;
indeg[trie[num][j]]--;
if(!indeg[trie[num][j]]) cnt++,que[++tail]=trie[num][j];
}
}
// for(int i=1;i<=nodenum;i++) printf("node:%d,fail:%d,indeg:%d,lc:%d,rc:%d,danger:%d\n",i-1,fail[i]-1,indeg[i],trie[i][0]-1,trie[i][1]-1,danger[i]);
// cout<<cnt<<' '<<nodenum;
if(cnt<nodenum) printf("TAK");
else printf("NIE");
}
int main(){
build_trie();
build_acm(1);
toposort();
return 0;
}
如果有问题,请告诉我哟~