题目描述

一位冷血的杀手潜入 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. Percona-Tookit工具包之pt-visual-explain

      Preface       As usual we will check the MySQL executed plan of SQL query by execute "explain ...

  2. Spring Boot2.4双数据源的配置

    相较于单数据源,双数据源配置有时候在数据分库的时候可能更加有利 但是在参考诸多博客以及书籍(汪云飞的实战书)的时候,发现对于spring boot1.X是完全没问题的,一旦切换到spring boot ...

  3. html5 手风琴菜单

    因为项目需要,现在需要做个手风琴菜单,于是自己就瞎整了一下,所用只是less.js  javascript  jquery效果如图: 具体代码如下: <!DOCTYPE html> < ...

  4. JS数组push一个对象

    这个是正确的数据添加对象 var dypieArr = []; var dyArr = []; var arrStr = ''; for(var i = 0; i < dataStreet.le ...

  5. Str_turn

    public class Str_turn { public static void main(String args[]) { String Str1 = new String("This ...

  6. C# 设置程序最小化到任务栏右下角,鼠标左键单击还原,右键提示关闭程序

    首先设置程序最小化到任务栏右下角 先给窗口添加一个notifyIcon控件 为notifyIcon控件设置ICO图标(不设置图标将无法在任务栏显示) 给notifyIcon控件添加点击事件 然后是最小 ...

  7. (数据科学学习手札19)R中基本统计分析技巧总结

    在获取数据,并且完成数据的清洗之后,首要的事就是对整个数据集进行探索性的研究,这个过程中会利用到各种描述性统计量和推断性统计量来初探变量间和变量内部的基本关系,本篇笔者便基于R,对一些常用的数据探索方 ...

  8. 2018 ccpc final I. Cockroaches

    I. Cockroaches time limit per test6. s memory limit per test256 MB inputstandard input outputstandar ...

  9. Angularjs+bootstrap 实现横向滑屏

    本地环境: AngularJS v1.3.2 angular-ui-bootstrap Version: 0.12.0 - 2014-11-16 实现代码:Html部分 <div ng-cont ...

  10. 6.JAVA知识点归纳整理

    一.jdk初识与HelloWord: 二.java基础: 2.1 标识符_关键字_数据类型 2.2 数据类型转换 2.3 程序编写格式 2.4 运算符 2.5 分支与for循环 2.6 while_b ...