考试的时候想了很多,不知道它那个概率究竟是怎么算。。没想到能蒙30分。rp爆发hhh

题解转自不知道哪里来的老师发的(代码出自自己)。

实际上警察就是两种结果——查到犯人或死亡,而死亡事件一定是包含在“调查未知身份的人”,也就是说调查未知身份的人越多,死亡概率就越高,所以我们要求的问题就是警察要尽可能少调查未知身份的人 
给出公式 P(死亡)=调查的未知身份的人数/总人数

“死亡”和”存活”是对立事件,而”存活”等价于”找到犯人” 所以 ans=1−P死亡 问题转化为求调查最少的未知身份人的人数 
同时我们发现,对于一个环(1认识2,2认识3,3认识1),我们是可以把他们看作一个人的,也就是说,只要调查了他们其中一个,其他两个我们一定可以安全到达(知道他是犯人或平民) 对于这个问题,我们使用tarjan对图进行缩点处理,然后我们所要调查的对象就是重构图中那些入度为0的点(没有人知道这些点里的人的身份),调查的未知身份的人数就是这些点的数量 (如果其中入度不为0,那么我们一定可以从一个入度为0的点走到这里,即我们调查这个点时是知道这里面的人的身份的) 
注意: 
有一个特殊情况,如果说至少有一个点,它只有一个人,他是完全孤立的(即没有人知道这个人的身份,他对外面的世界也一无所知)或者他认识的每个人都被除他以外的其他人所认识(即它所能到达的点的入度>1),那么我们在安全调查完除他以外的其他人后,他一定是杀手(但在图上他属于未知身份的人),我们不必去调查他,直接抓起来就可以了,所以调查未知身份的人数要– 1(我们可以想得简单些,比如n=1时这个人一定是杀手,即P存活=1)

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define N 500000
int n,m;
int low[N],dfn[N],stack[N],instack[N],belong[N];
int peo[N];
struct haha{
	int next,to;
};
haha edgechu[N],edge[N];
int head[N],cnt=1,cntchu=1,headchu[N];
void add(int u,int v){
	edge[cnt].to=v;
	edge[cnt].next=head[u];
	head[u]=cnt++;
}
void addchu(int u,int v){
	edgechu[cntchu].to=v;
	edgechu[cntchu].next=headchu[u];
	headchu[u]=cntchu++;
}
int ji=1,hea,cn=1;
void tarjan(int now){
	low[now]=dfn[now]=ji++;
	stack[++hea]=now;
	instack[now]=1;
	for(int i=headchu[now];i;i=edgechu[i].next){
		int to=edgechu[i].to;
		if(dfn[to]==-1){
			tarjan(to);
			low[now]=min(low[now],low[to]);
		}
		else{
			if(instack[to]){
				low[now]=min(low[now],dfn[to]);
			}
		}
	}
	if(low[now]==dfn[now]){
		int temp;
		while(1){
			temp=stack[hea--];
			belong[temp]=cn;
			instack[temp]=0;
			peo[cn]++;
			if(temp==now)
			  break;
		}
		cn++;
	}
}
int in[N],out[N];
int ans;
int flag[N];
int main(){
	freopen("killer.in","r",stdin);
	freopen("killer.out","w",stdout);
	scanf("%d%d",&n,&m);
	memset(dfn,-1,sizeof(dfn));
	pos(i,1,m){
		int x,y;
		scanf("%d%d",&x,&y);
		addchu(x,y);
	}
	pos(i,1,n){
	   if(dfn[i]==-1)
		tarjan(i);
	}
	cn--;
	pos(i,1,n){
		for(int v=headchu[i];v;v=edgechu[v].next){
			int j=edgechu[v].to;
			if(belong[i]!=belong[j]){
				add(belong[i],belong[j]);
				in[belong[j]]++;
				out[belong[i]]++;
			}
		}
	}
	pos(i,1,cn){
		if(in[i]==0){
			ans++;
		}
	}
	pos(i,1,cn){
		if(peo[i]==1){
			if(in[i]==0&&out[i]==0){
				ans--;
				double temp=(double)(n-ans)/n;
				printf("%0.6lf",temp);
				return 0;
			}
			else{
				for(int j=head[i];j;j=edge[j].next){
					int to=edge[j].to;
					if(in[to]>1){
						flag[i]++;
					}
				}
				if(flag[i]==out[i]&&(flag[i])){
					ans--;
					double temp=(double)(n-ans)/n;
					printf("%0.6lf",temp);
					return 0;
				}
			}
		}
	}
	double temp=(double)(n-ans)/n;
	printf("%0.6lf",temp);
	return 0;
}

  

[bzoj 2438][中山市选2011]杀人游戏 概率+tarjan的更多相关文章

  1. bzoj 2438: [中山市选2011]杀人游戏【tarjan】

    没看太懂题意orz 最优的是tarjan缩点之后问入度为0的点,因为问这个点可以知道整个块的情况 答案是这ans个入度为0的点都不是杀手的概率\( \frac{n-ans}{n} \) 但是有特殊情况 ...

  2. bzoj 2438 [中山市选2011]杀人游戏(SCC+概率)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2438 [题意] N个人中有一个杀手,每次询问一个人可能被杀或被告知其认识的人中谁是杀手 ...

  3. BZOJ——2438: [中山市选2011]杀人游戏

    http://www.lydsy.com/JudgeOnline/problem.php?id=2438 Description 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个 ...

  4. BZOJ 2438: [中山市选2011]杀人游戏

    Description 给你一个有向图,求至少询问多少次能够得到全部点的信息. Sol Tarjan + 强连通分量缩点 + 判断. 先缩点,如果我们知道了强连通分量里的任意一个点,我们就可以知道这些 ...

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

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

  6. BZOJ 2438 [中山市选2011]杀人游戏 ——期望DP

    发现每一次死亡的几率相等,所以只需要判断最少问多少人即可. 并且环上的点任意询问都可以. 所以直接Tarjan缩点,然后计算入度为0的点的数目. 但是还有一些情况的时候会减少一次询问,比如说:$1-& ...

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

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

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

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

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

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

随机推荐

  1. Generic(泛型)

    什么是泛型:"通过参数化类型来实现在同一份代码上操作多种数据类型.利用"参数化类型"将类型抽象化,从而实现灵活的复用". 简单来说泛型就是为了使一些代码能够重复 ...

  2. 【Python3之多进程】

    一.进程和线程的简单解释 进程(process)和线程(thread)是操作系统的基本概念,但是它们比较抽象,不容易掌握. 用生活举例: (转自阮一峰网络日志) 1.计算机的核心是CPU,它承担了所有 ...

  3. 我的学习之路_第二十八章_JQuery 和validator插件

    jQuery 利用jQuery进行遍历 js原生: for(var i=0;i>?;i++){ } jQuery: 方式一: 想要遍历的jQuery对象.each(function(index, ...

  4. 刨根究底字符编码之十四——UTF-16究竟是怎么编码的

    UTF-16究竟是怎么编码的 1. 首先要注意的是,代理Surrogate是专属于UTF-16编码方式的一种机制,UTF-8和UTF-32是不用代理的. 如前文所述,为了让UTF-16能继续编码基本平 ...

  5. 18-EasyNetQ:发生错误的情况

    这一篇文章让我们看看在消息系统中可能发生的各种错误的情况下,看下EasyNetQ如何处理它们. 订阅服务挂了 当你写了一个windows 服务,用来订阅一个NewCustomerMessage消息. ...

  6. 阅读MDN文档之布局(四)

    Introducing positioning Static positioning Relative positioning Introducing top, bottom, left and ri ...

  7. 同一个sql在不同的oracle中执行时间不一样

    最近因为某些原因不得不重新配置服务器的环境,当然就是一些简单的程序运行环境,包括tomcat .oracle和其他的一些.原本觉得还蛮简单的东西,但是当我部署完成后在运行程序的过程中发现了一些隐性因数 ...

  8. 标准IO:常用函数集合

    stdio : 标准IO  (1) 流(stream)和文件(file) 流和文件 在Turbo C2.0中是有区别的, Turbo C2.0 为编程者和被访问的设备之间提供了一层抽象的东西, 称之为 ...

  9. 51nod_1417:天堂里的游戏

    题目链接: https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1417 假设 ans=n/m,C=(A+B)/2 若出正面 ...

  10. 浅谈JVM与内存分配

    一.程序内存分配 初始内存分配 当一个程序准备运行时,它首先向java虚拟机要内存,但是java虚拟机本身没有权限,它只能向操作系统申请内存,此时java虚拟机会拥有一个初始内存, 此处额外说明一下e ...