题目描述

一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 N 个人里面,查出谁是杀手。警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民。 假如查证的对象是杀手, 杀手将会把警察干掉。现在警察掌握了每一个人认识谁。每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少?

输入

第一行有两个整数 N,M。 
接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识 x) 。

输出

仅包含一行一个实数,保留小数点后面 6 位,表示最大概率。

样例输入

5 4
1 2
1 3
1 4
1 5

样例输出

0.800000


题解

Tarjan

显然只需要查证所有 缩点后入度为0的强连通分量中的任意一个点 即可,即必须查证的人的个数等于入度为0的强连通分量个数。

但是这并不一定是最优解。考虑一种情况:

这时只需要查证2(或者查证1)即可,可以不查证1(或2)。

具体原因是:一个入度为0的强连通分量大小为1,如果它指向的所有点都不仅由它到达(即减去它到其的边数后入度不为0),那么可以先查证其它点,直到最后仅剩下这个点,即可不查证该点。

于是需要再统计一下是否有这种情况。具体方法:枚举每个点,判断它所有能够到达的点是否仅由它到达即可。注意这样的点只能保留1个(多了无法排除),因此需要及时终止循环。

最后 (n-必须查证的人)/n 即为存活概率。

时间复杂度$O(n+m)$

#include <cstdio>
#include <algorithm>
#define N 100010
#define M 300010
using namespace std;
int head[N] , to[M] , next[M] , cnt , deep[N] , low[N] , tot , vis[N] , ins[N] , sta[N] , top , bl[N] , si[N] , num , ind[N];
inline void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void tarjan(int x)
{
int i;
deep[x] = low[x] = ++tot , vis[x] = ins[x] = 1 , sta[++top] = x;
for(i = head[x] ; i ; i = next[i])
{
if(!vis[to[i]]) tarjan(to[i]) , low[x] = min(low[x] , low[to[i]]);
else if(ins[to[i]]) low[x] = min(low[x] , deep[to[i]]);
}
if(deep[x] == low[x])
{
int t;
num ++ ;
do
{
t = sta[top -- ] , si[num] ++ ;
ins[t] = 0 , bl[t] = num;
}while(t != x);
}
}
bool judge(int x)
{
int i;
bool flag = 1;
for(i = head[x] ; i ; i = next[i]) ind[bl[to[i]]] -- ;
for(i = head[x] ; i ; i = next[i])
if(!ind[bl[to[i]]])
flag = 0;
for(i = head[x] ; i ; i = next[i]) ind[bl[to[i]]] ++ ;
return flag;
}
int main()
{
int n , m , i , x , y , ans = 0;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y);
for(i = 1 ; i <= n ; i ++ )
if(!vis[i])
tarjan(i);
for(x = 1 ; x <= n ; x ++ )
for(i = head[x] ; i ; i = next[i])
if(bl[x] != bl[to[i]])
ind[bl[to[i]]] ++ ;
for(i = 1 ; i <= num ; i ++ )
if(!ind[i])
ans ++ ;
for(i = 1 ; i <= n ; i ++ )
if(si[bl[i]] == 1 && !ind[bl[i]] && judge(i))
break;
if(i <= n) ans -- ;
printf("%.6lf\n" , (double)(n - ans) / n);
return 0;
}

【bzoj2438】[中山市选2011]杀人游戏 Tarjan的更多相关文章

  1. BZOJ2438: [中山市选2011]杀人游戏(tarjan)

    题意 题目链接 Sol 这题挺考验阅读理解能力的.. 如果能读懂的话,不难发现这就是在统计有多少入度为\(0\)的点 缩点后判断一下即可 当然有一种例外情况是\(1 -> 3, 2 -> ...

  2. bzoj2438: [中山市选2011]杀人游戏(强联通+特判)

    2438: [中山市选2011]杀人游戏 题目:传送门 简要题意: 给出n个点,m条有向边,进行最少的访问并且可以便利(n-1)个点,求这个方案成功的概率 题解: 一道非常好的题目! 题目要知道最大的 ...

  3. 【BZOJ2438】 [中山市选2011]杀人游戏 tarjan强连通分量+缩点

    Description 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是 ...

  4. bzoj2438[中山市选2011]杀人游戏

    Description 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面, 查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他 认识的人, ...

  5. BZOJ2438:[中山市选2011]杀人游戏(强连通分量)

    Description 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面,查出谁是杀手.警察能够对每一个人 进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是 ...

  6. [BZOJ 2438] [中山市选2011]杀人游戏 Tarjan缩点

    这个题很容易想到正解就是缩点找入度为零的点,那么我们考虑一种特殊情况就是,一个入度为零的点我们不访问他就知道他是不是凶手,那么这样的话就是:I. 他是一个真·孤立的点 II. 他在图里但是在他的强联通 ...

  7. BZOJ_2438_[中山市选2011]杀人游戏 _强连通分量

    BZOJ_2438_[中山市选2011]杀人游戏 _强连通分量 Description 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面,查出谁是杀手.警察能够对每一个人 ...

  8. 【bzoj2438】 中山市选2011—杀人游戏

    http://www.lydsy.com/JudgeOnline/problem.php?id=2438 (题目链接) 题意 n个点的有向图,其中有一个是杀手,每个人成为杀手的概率相同.警察询问一个人 ...

  9. [bzoj 2438][中山市选2011]杀人游戏 概率+tarjan

    考试的时候想了很多,不知道它那个概率究竟是怎么算..没想到能蒙30分.rp爆发hhh 题解转自不知道哪里来的老师发的(代码出自自己). 实际上警察就是两种结果——查到犯人或死亡,而死亡事件一定是包含在 ...

随机推荐

  1. 【BGP的基本配置】

    BGP的基本配置 一:根据项目需求搭建好拓扑图如下 二:配置 1:首先进行理论分析:RT1和RT2,3分别属于不同的AS;在RT1和RT2之间建立EBGP关系,在确保RT3可以学到RT1的8.1.1. ...

  2. thinkphp 3.2中依靠关联模型来关联三个表

    这里说的是用thinkphp3.2关联模型关联三个表 根据用户表查询出三个表的数据,需要两个model来配合,第一个model是根据user表来查询到班级的信息,然后第二个model是根绝banji中 ...

  3. atlas+mysql部署mysql读写分离

    1.atlas 简介 Atlas是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目.它在MySQL官方推出的MySQL-Proxy 0.8.2版本的基 ...

  4. golang 三个点的用法

    已经忘了这是第几次查这个用法了,还是记一下吧~ ^ _ ^ 本文同时发表在https://github.com/zhangyachen/zhangyachen.github.io/issues/137 ...

  5. python2.7入门--- 日期和时间

        Python 程序能用很多方式处理日期和时间,转换日期格式是一个常见的功能.我们今天就来看一下这方面,首先得知道,Python 提供了一个 time 和 calendar 模块可以用于格式化日 ...

  6. Vue 去脚手架

    上回模仿了一个nw,按照原理说,简单. 今天说Vue,脚手架是个好东西,做项目都给你配置好,不过对于我这种只想做一个界面的人来说,有点儿太大了,用不上. 如果说,不用脚手架要面临哪些问题呢. 1. 组 ...

  7. 算法-----数组------ 数组中的第K个最大元素

    在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 ...

  8. Mysql 启动运行

    MYSQL默认端口:3306用户: root   也可自己添加用户启动数据库服务名: MYSQL (在安装的时候会设置) 在开始菜单栏->附件->右键命令提示符->以管理员身份运行: ...

  9. OrCAD把原理图中的器件添加到原理图库

    1. 在使用OrCAD的时候,有时需要把别人的原理图里面的器件添加到自己的原理图库,方便以后使用,具体操作如下,依次选择Design Cache---元器件--Copy 2. 选中要存放的原理图库,鼠 ...

  10. 如何从“点子”落地到“执行”?—完整解析1个手游传播类mini项目的进化

    本文来自网易云社区 作者:林玮园 从点子到落地,是不确定到确定的过程,是从模糊概念到具体现实的实现过程.无论什么点子,在落地变现的过程中都会有很多疑问产生. 首先,不确定点子本身是否成立.点子的背后是 ...