题意

二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码。如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的。现在委员会已经找出了所有的病毒代码段,试问,是否存在一个无限长的安全的二进制代码。

示例:

例如如果{011, 11, 00000}为病毒代码段,那么一个可能的无限长安全代码就是010101…。如果{01, 11, 000000}为病毒代码段,那么就不存在一个无限长的安全代码。

任务:

请写一个程序:

1.在文本文件WIR.IN中读入病毒代码;

2.判断是否存在一个无限长的安全代码;

3.将结果输出到文件WIR.OUT中。

输入格式:

在文本文件WIR.IN的第一行包括一个整数n(n\le 2000)(n≤2000),表示病毒代码段的数目。以下的n行每一行都包括一个非空的01字符串——就是一个病毒代码段。所有病毒代码段的总长度不超过30000。

输出格式:

在文本文件WIR.OUT的第一行输出一个单词:

TAK——假如存在这样的代码;

NIE——如果不存在。

题解

很容易想到将病毒串放入Trie树,补全后,如果能找到一个不经过任何串末尾的环就有一个安全代码

考虑如何找环,本来想的是拓扑排序,不过就算找出一个环,也很难判断是否含末尾点

然后又不小心听到了dfs,想了想很有道理,于是写出了如下东西

结果WA了一片,第一个样例就错了.....

那考虑为什么会这样,按照上面的写法,下个点访问过一定是环吗?

不一定,补全后就是一个有向图,所以我们拿有向图举例

如果先从1遍历完,然后回到1,再从2到1时,就会判断是环

然而不是,因为这是有向图,如果是无向图的话确实有环。

那么考虑怎么更正

在回溯时删除vis标记即可,这样能否找到环?

答案是确定的,因为会遍历到每个路径

#include<bits/stdc++.h>
using namespace std;const int maxn=30005;
int n,num;
int go[maxn][2],fail[maxn];
char s[maxn];
bool end[maxn],vis[maxn];void extend(int len){int now=0;for(int i=0;i<len;i++){int c=s[i]-'0';if(!go[now][c]) go[now][c]=++num;now=go[now][c];}end[now]=true;
}queue<int> q;void get_fail(){if(go[0][0]) q.push(go[0][0]);if(go[0][1]) q.push(go[0][1]);while(!q.empty()){int now=q.front();q.pop();for(int i=0;i<=1;i++)if(!go[now][i]) go[now][i]=go[fail[now]][i];else {fail[go[now][i]]=go[fail[now]][i];end[go[now][i]]|=end[fail[go[now][i]]];q.push(go[now][i]);}}
}bool dfs(int now){if(end[now]) return false;for(int i=0;i<=1;i++)if(!vis[go[now][i]]){vis[go[now][i]]=true;if(dfs(go[now][i])) return true;vis[go[now][i]]=false;}else if(!end[go[now][i]]) return true;return false;
}int main(){scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%s",s),extend(strlen(s));get_fail();vis[0]=true;printf("%s",dfs(0) ? "TAK" : "NIE");
}

View Code

然后在bzoj上就T了,一看评论才知道。

需要两个bool数组,vis记录是否访问过,访问过就不访问,达到剪枝目的,sta记录是否在当前路径

不会错吗?考虑如果下一个要遍历的点在我们要的环中,但它访问过了,当第一次访问它时,它就应该找出环,所以不可能。

luogu真的有点小水

#include<bits/stdc++.h>
using namespace std;const int maxn=30005;
int n,num;
int go[maxn][2],fail[maxn];
char s[maxn];
bool end[maxn],vis[maxn],sta[maxn];//是否访问过,是否在当前路径 void extend(int len){int now=0;for(int i=0;i<len;i++){int c=s[i]-'0';if(!go[now][c]) go[now][c]=++num;now=go[now][c];}end[now]=true;
}queue<int> q;void get_fail(){if(go[0][0]) q.push(go[0][0]);if(go[0][1]) q.push(go[0][1]);while(!q.empty()){int now=q.front();q.pop();for(int i=0;i<=1;i++)if(!go[now][i]) go[now][i]=go[fail[now]][i];else {fail[go[now][i]]=go[fail[now]][i];end[go[now][i]]|=end[fail[go[now][i]]];q.push(go[now][i]);}}
}bool dfs(int now){if(end[now]) return false;for(int i=0;i<=1;i++)if(!vis[go[now][i]]){sta[go[now][i]]=true;vis[go[now][i]]=true;if(dfs(go[now][i])) return true;sta[go[now][i]]=false;}else if(sta[go[now][i]]&&!end[go[now][i]]) return true;return false;
}int main(){scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%s",s),extend(strlen(s));get_fail();sta[0]=vis[0]=true;printf("%s",dfs(0) ? "TAK" : "NIE");
}

View Code

转载于:https://www.cnblogs.com/sto324/p/11209785.html

[POI2000]病毒(补全AC自动机)相关推荐

  1. Trie树实现前缀自动补全 + AC自动机实现敏感词过滤

    文章目录 背景 扩展 AC自动机 背景 最近参与了某业务系统的开发, 需要根据城市的名字简称,找到其官方的完整名称.比如云南的大理,其实其完整的名称是大理白族自治州.可以参考官方的行政区划,点这里. ...

  2. hdu 2896 病毒侵袭(AC自动机)

    病毒侵袭                                                                           Time Limit: 2000/1000 ...

  3. HDOJ 2896 病毒侵袭(AC自动机入门)

    题意: 求感染病毒的网站,并输出其感染的病毒特征码编号. 思路: AC自动机入门,思路同 HDOJ 2222 #include <iostream> #include <deque& ...

  4. HDU 2896 病毒侵袭【AC自动机】

    Problem Description 当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻....在这样的时刻,人们却异常兴奋--我们能在有生之年看到500年一遇的世界奇观,那是多么幸福 ...

  5. HDU 2896 病毒侵袭(AC自动机/模板题)

    传送门 病毒侵袭 Time Limit: 2000/1000 MS (Java/Others)            Memory Limit: 131072/131072 K (Java/Other ...

  6. POJ - 2778 DNA Sequence(AC自动机+矩阵快速幂)

    题目链接:点击查看 题目大意:给出 n 个长度不大于 10 的字符串表示病毒串,再给出一个长度 len ,问长度为 len 的字符串中,有多少个字符串不含有病毒串作为子串 题目分析:因为病毒串的长度和 ...

  7. bzoj 2938: [Poi2000]病毒(AC自动机)

    2938: [Poi2000]病毒 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 1085  Solved: 541 [Submit][Status] ...

  8. BZOJ2938[Poi2000]病毒——AC自动机

    题目描述 二进制病毒审查委员会最近发现了如下的规律:某些确定的二进制串是病毒的代码.如果某段代码中不存在任何一段病毒代码,那么我们就称这段代码是安全的.现在委员会已经找出了所有的病毒代码段,试问,是否 ...

  9. BZOJ2938: [Poi2000]病毒(AC自动机)

    Orz wlp 5min讲完后缀数组 题意 给出$n$个0, 1串 问是否可以构造出一个无限长的字符串使其不包含任意串 Sol 刚开始我试图假装自己不知道这是个AC自动机的题然后来做.发现根本不可能q ...

  10. 【BZOJ2938】病毒,AC自动机练习

    传送门(权限题) 2938: [Poi2000]病毒 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 462 Solved: 240 [Submit][S ...

最新文章

  1. Android 中的安全机制
  2. Zookeeper集群配置
  3. Cannot open D:\Program Files\Anaconda3\Scripts\pip-script.py
  4. php 文件管理系统_如何编写程序实现图书管理系统的个人图书借阅查询功能
  5. 独家 | 手把手教你用Python 3创建用于机器学习开发的Linux虚拟机(附安装教程代码)...
  6. Linux 及其它类 Unix 系统的系统服务管理和控制程序(初始化系统/init system)简单梳理
  7. 为什么说 Transformer 就是图神经网络?
  8. 高级Bash脚本编程入门
  9. ir2110s驱动工作原理
  10. java rrd_java利用rrd4j做服务监控的图片
  11. MOS管的行业应用领域-KIA MOS管
  12. JS实现合并单元格的两种方法
  13. 阿里云培训-负载均衡(CLB/ALB)
  14. 宇视NVR录像机下载录像没有声音如何解决
  15. SLAM笔记(六)直接法介绍
  16. 计算机学习资料(全)——含视频资料
  17. 20155214曾士轩 2016-2017-2 《Java程序设计》第1周学习总结
  18. HER608-ASEMI整流二极管R-6轴向插件封装
  19. mysql read rnd next_16.9.6. 实施rnd_next()函数
  20. 使用 GCD 实现倒计时效果

热门文章

  1. C++ 从入门到入土(English Version)Section 6: Pointers and Call by Reference
  2. HDOJ--1864--最大报销额
  3. 匹配中文字符的正则表达式
  4. ubuntu mysql远程连接
  5. 我与WCF有个约会之牵手篇-第一个WCF示例程序
  6. C++实现LRU(Least-Recently Used)缓存算法
  7. python的基本概念_Python必学基础概念
  8. 计算机应用基础实例,计算机应用基础案例教程(Windows 7+Office 2010)
  9. Nginx源码分析 - 模块的赋值及编号 --- 方便了解nginx模块
  10. redis分布式锁的 5个坑