【BZOJ2438】[中山市选2011]杀人游戏 Tarjan

【BZOJ2438】[中山市选2011]杀人游戏

Description

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

Input

第一行有两个整数 N,M。 
接下来有 M 行,每行两个整数 x,y,表示 x 认识 y(y 不一定认识 x,例如胡*锦*涛同志) 。

Output

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

Sample Input

5 4
1 2
1 3
1 4
1 5

Sample Output

0.800000

HINT

警察只需要查证 1。假如1是杀手,警察就会被杀。假如 1不是杀手,他会告诉警察 2,3,4,5 谁是杀手。而 1 是杀手的概率是 0.2,所以能知道谁是杀手但没被杀的概率是0.8。对于 100%的数据有 1≤N ≤  10 0000,0≤M ≤  30 0000

题解:结论:ans=1-(最少查证的人数/总人数)

我们先跑Tarjan缩点,然后每个入度为0的强联通分量我们都至少查证其中的一个人,其余的都没有必要查证,所以最少查证的人数就是入度为0的强联通分量的个数。

咦?哪里不对?

如果只有2个人,他们互相不认识,那么我们只需要查证一个人就能直接知道另一个人的身份。所以如果存在某个入度为0,大小为1,且指向的其他强联通分量入度都>1时,答案--。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int maxn=100010,maxm=300010;
int n,m,cnt,tot,top,ans,sum;
int to[maxm],next[maxm],head[maxn],dep[maxn],low[maxn],ins[maxn],sta[maxn],d[maxn],bel[maxn],vis[maxn];
vector<int> v[maxn];
void add(int a,int b)
{
	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
void tarjan(int x)
{
	dep[x]=low[x]=++tot,ins[x]=1,sta[++top]=x;
	for(int i=head[x];i!=-1;i=next[i])
	{
		if(!dep[to[i]])	tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
		else if(ins[to[i]])	low[x]=min(low[x],dep[to[i]]);
	}
	if(dep[x]==low[x])
	{
		sum++;
		int t;
		do
		{
			t=sta[top--],v[sum].push_back(t),bel[t]=sum,ins[t]=0;
		}while(t!=x);
	}
}
bool islast(int x)
{
	int i,j,flag=0;
	for(i=0;i<v[x].size();i++)
		for(j=head[v[x][i]];j!=-1;j=next[j])
			if(d[bel[to[j]]]==1)	return 0;
	return 1;
}
int main()
{
	n=rd(),m=rd();
	int i,j,k,a,b;
	memset(head,-1,sizeof(head));
	for(i=1;i<=m;i++)	a=rd(),b=rd(),add(a,b);
	for(i=1;i<=n;i++)	if(!dep[i])	tarjan(i);
	for(i=1;i<=sum;i++)
		for(j=0;j<v[i].size();j++)
			for(k=head[v[i][j]];k!=-1;k=next[k])
				if(bel[to[k]]!=i&&vis[bel[to[k]]]!=i)
					vis[bel[to[k]]]=i,d[bel[to[k]]]++;
	for(i=1;i<=sum;i++)	if(!d[i])	ans++;
	for(i=1;i<=sum;i++)
	{
		if(!d[i]&&v[i].size()==1&&islast(i))
		{
			ans--;
			break;
		}
	}
	printf("%.6lf",(1.0*n-ans)/n);
	return 0;
}
时间: 2024-12-09 16:22:14

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

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

2438: [中山市选2011]杀人游戏 题目:传送门 简要题意: 给出n个点,m条有向边,进行最少的访问并且可以便利(n-1)个点,求这个方案成功的概率 题解: 一道非常好的题目! 题目要知道最大的存活概率,那么也就是找到直接找到杀手的最小概率 那么我们采用强联通缩点: 统计每个联通分量的入度,如果入度为0(证明除此联通分量里的点,没有人可以知道连通分量里的信息,那就一定要先选一个人访问),那么sum++(因为依据题意,假如问到连通分量里的任意一个人,只要ta不是杀手,那么一定可以安全的遍历强

BZOJ 2438 中山市选 2011 杀人游戏 Tarjan

题目大意:给出一张有向人物关系图,告诉你谁认识谁,认识具有传递性.其中有一个人是犯人.现在警察要调查谁是犯人.他可以问任何人.但是如果他问到了犯人,那么它就会死.如果他问到的一个人认识犯人,这个人就会告诉警察谁是犯人.问警察保证自身安全并知道犯人是谁的概率最大是多少. 思路:这个题前一阵子重测了,加强了数据,卡掉了网上一片AC代码.. 正解并不是很难想.首先先缩点,整个图变成拓扑图,之后会出现一些类似根的东西,这些scc入度为0,只要警察询问了这些scc每一个中的任意一个,就肯定能知道谁是犯人.

BZOJ 2438 中山市选2011 杀人游戏 Tarjan

题目大意:有n个人,其中一个是杀手,可以询问一些人,如果是杀手就会死,如果是平民,他会告诉你他认识的人中有谁是杀手有谁是平民 警告:数据有误,请谨慎提交! 易知如果我需要访问x个人,那么答案就是1-x/n 我们需要访问最少的人 如果我访问的人是平民,那么这个点所有的后继我都能知道 于是Tarjan缩点之后入度为零的点就是答案 但是还有一个问题 比如说这组样例 3 1 1 2 我访问了1,那么1和2是不是凶手我就都知道了 既然只有三个人,我知道1和2是不是凶手,那么3也一定知道 没必要去访问3 于

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

感觉今天状态起飞了!!!之前留的坑一调就A了,舒服!!! 那么这题之前一看就觉得,假如一个人没人认识实际上他必须查一下,那么我第一次做的时候就把他抽象成了很多棵树,然后我只查树根,然后下面的每一层我都知道身份,那就没有生命之忧了.然后特判一下有一个人没人认识tata也不认识别人,就是自己独立出来的,那他最后留下来实际上不用查. 然后实际上这题怎么可能这么简单,肯定会构环的,那么就考虑强连通缩点,那么这题难就难在怎么判最后查剩一个人的情况了,那么具体怎么做呢?首先这个点入度肯定为0的,再者这个联通

[中山市选2011]杀人游戏

[中山市选2011]杀人游戏 时间限制: 1 Sec  内存限制: 128 MB提交: 64  解决: 33[提交][状态][讨论版] 题目描述 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面,查出谁是杀手. 警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人, 谁是杀手, 谁是平民. 假如查证的对象是杀手, 杀手将会把警察干掉. 现在警察掌握了每一个人认识谁. 每一个人都有可能是杀手,可看作他们是杀手的概率是相同的. 问:根据最优的情况,保

bzoj 2438: [中山市选2011]杀人游戏 (强联通分量 Tarjan)

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

[补档][中山市选2011]杀人游戏

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

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

Description 给你一个有向图,求至少询问多少次能够得到全部点的信息. Sol Tarjan + 强连通分量缩点 + 判断. 先缩点,如果我们知道了强连通分量里的任意一个点,我们就可以知道这些点的信息,和这些点所连接的其他点的信息,显然我们需要知道的就是缩点后入度为0的点. 然后还有最后一个入度为0的单点,并且他的所有儿子都能被其他节点访问,那么最后就可以直接推断出这个点,所以要删去. Code #include<cstdio> #include<stack> #inclu

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

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2438 [题意] N个人中有一个杀手,每次询问一个人可能被杀或被告知其认识的人中谁是杀手谁是平民,问不被杀的情况下知道谁是杀手的概率. [思路] 对于一个scc,如果我们询问一个不是杀手的人,就可以成功遍历整个scc. 求scc,然后缩点. 对于每一个入度为0的scc,我们需要去询问一下,那么被杀的概率为1/n * ans.ans为入度为0的scc个数. 但还有一种特殊的情况,如果一个