bzoj 2938: [Poi2000]病毒

2938: [Poi2000]病毒

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 1111  Solved: 556
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

3
01
11
00000

Sample Output

NIE
/*
    首先我们把所有串建一个AC自动机
    方便起见我们直接把fail指针合并到子结点
    如果一个串能无限长,也就是说它可以在AC自动机上一直进行匹配但就是匹配不上
    也就是说匹配指针不能走到val为1的结点,设这个点为x
    即root..x是一个病毒串
    那么fail指针指向x的y也不能走
    因为root..x是root..y的一个后缀
    处理出来判断有向图是否有环
    dfs即可
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define maxn 30010
int n,sz=1,a[maxn][2],fail[maxn],word[maxn];
bool ins[maxn],vis[maxn];
char s[maxn];
void insert(){
    int now=1,len=strlen(s);
    for(int i=0;i<len;i++){
        int t=s[i]-'0';
        if(!a[now][t])a[now][t]=++sz;
        now=a[now][t];
    }
    word[now]=1;
}
void acmach(){
    queue<int>q;
    q.push(1);fail[1]=0;
    while(!q.empty()){
        int now=q.front();q.pop();
        for(int i=0;i<2;i++){
            if(!a[now][i]){a[now][i]=a[fail[now]][i];continue;}
                      int k=fail[now];
            while(!a[k][i])k=fail[k];
            fail[a[now][i]]=a[k][i];
            word[a[now][i]]|=word[a[k][i]];
            q.push(a[now][i]);
        }
    }
}
bool dfs(int x){//判断是否有环 
    ins[x]=1;
    for(int i=0;i<2;i++){
        if(ins[a[x][i]])return 1;
        if(vis[a[x][i]]||word[a[x][i]])continue;
        vis[a[x][i]]=1;
        if(dfs(a[x][i]))return 1;
    }
    ins[x]=0;
    return 0;
}
int main(){
    for(int i=0;i<2;i++)a[0][i]=1;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        insert();
    }
    acmach();
    if(dfs(1))printf("TAK");
    else printf("NIE");
    return 0;
}

 

posted @ 2017-12-23 17:54  Echo宝贝儿  阅读(222)  评论(0编辑  收藏  举报