我的题解(2)-病毒

先上题:

题目描述

二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。
示例:
例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。
任务:
请写一个程序:
l         读入病毒代码;
2         判断是否存在一个无限长的安全代码;
3         将结果输出

输入

第一行包括一个整数n,表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。

输出

你应在在文本文件WIN.OUT的第一行输出一个单词:
         TAK——假如存在这样的代码;
         NIE——如果不存在。

样例输入

3
01
11
00000

样例输出

NIE

首先,别考虑直接输答案

来说说思路:
trie树显然不行(关于trie树,就不多说了)。

So-用trie图。trie图可以使用后缀进行查找,让查找在图中畅通无阻。
重点是:如何判断可以出现无限长的代码呢?
想想,当图中出现 且环中没有危险节点时,我们就按此环循环,可出现无限长代码。
使用拓扑排序可判断环(当前节点的入度都≥1时,有环。x的入度就是指向x节点的节点的个数)。

具体步骤:
1.创建trie树;
2.连接虚边,创建trie图;
3.进行搜索,消掉入度为零的点,减掉 入度为零的点指向的点的一个入度.

代码(请不要管注释,为调试信息-我的代码错了13次 ):

#include
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<
如果有问题,请告诉我哟~

你可能感兴趣的:(题解)