首页 > 其他 > 详细

【bzoj2938】[Poi2000]病毒

时间:2017-01-09 15:58:29      阅读:140      评论:0      收藏:0      [点我收藏+]

题目描述

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

输入

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

输出

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

样例输入

3
01
11
00000

样例输出

NIE


题解

AC自动机

如果一个串能无限长,那么说明它可以一直匹配,而始终不匹配病毒串。

每次查找到下一个字符时,只有两种可能:

      (1)存在子节点,进入该子节点。

      (2)不存在子节点,进入fail节点,直至存在子节点。

那么是否能无限匹配,就转化为有没有相应的环。

这里为了方便,将fail合并到子节点。

除了排除病毒串节点以外,还应排除fail指向病毒串的节点,因为该串后缀为病毒串前缀。

然后dfs判环即可。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <queue>
 4 using namespace std;
 5 queue<int> q;
 6 int nt[30001][2] , fail[30001] , cnt[30001] , tot = 1;
 7 char str[30001];
 8 bool vis[30001] , ins[30001] , flag;
 9 int deep[30001] , low[30001] , sta[30001] , ind , h;
10 void build()
11 {
12     int u , t , i;
13     q.push(1);
14     nt[0][0] = nt[0][1] = 1;
15     while(!q.empty())
16     {
17         u = q.front();
18         q.pop();
19         for(i = 0 ; i < 2 ; i ++ )
20         {
21             if(nt[u][i])
22             {
23                 q.push(nt[u][i]);
24                 t = fail[u];
25                 while(t && !nt[t][i])
26                     t = fail[t];
27                 fail[nt[u][i]] = nt[t][i];
28                 cnt[nt[u][i]] |= cnt[nt[t][i]];
29             }
30             else
31                 nt[u][i] = nt[fail[u]][i];
32         }
33     }
34 }
35 bool dfs(int x)
36 {
37     ins[x] = vis[x] = 1;
38     int i , y;
39     for(i = 0 ; i < 2 ; i ++ )
40     {
41         y = nt[x][i];
42         if(ins[y] || (!vis[y] && !cnt[y] && dfs(y)))
43             return 1;
44     }
45     ins[x] = 0;
46     return 0;
47 }
48 int main()
49 {
50     int n , i , t , l;
51     scanf("%d" , &n);
52     while(n -- )
53     {
54         scanf("%s" , str);
55         l = strlen(str);
56         t = 1;
57         for(i = 0 ; i < l ; i ++ )
58         {
59             if(!nt[t][str[i] - 0])
60                 nt[t][str[i] - 0] = ++tot;
61             t = nt[t][str[i] - 0];
62         }
63         cnt[t] = 1;
64     }
65     build();
66     printf("%s\n" , dfs(1) ? "TAK" : "NIE");
67     return 0;
68 }

 

【bzoj2938】[Poi2000]病毒

原文:http://www.cnblogs.com/GXZlegend/p/6265366.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!