ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【P4819】杀人游戏

2020-06-11 19:51:30  阅读:297  来源: 互联网

标签:cnt include 游戏 int 杀手 tot low 杀人 P4819


题目

题目链接:https://www.luogu.com.cn/problem/P4819

一位冷血的杀手潜入 Na-wiat,并假装成平民。警察希望能在 \(n\) 个人里面,查出谁是杀手。警察能够对每一个人进行查证,假如查证的对象是平民,他会告诉警察,他认识的人,谁是杀手,谁是平民。假如查证的对象是杀手,杀手将会把警察干掉。现在警察掌握了每一个人认识谁。每一个人都有可能是杀手,可看作他们是杀手的概率是相同的。

问:根据最优的情况,保证警察自身安全并知道谁是杀手的概率最大是多少。

思路

考虑到在一个强连通分量里,问任意一个人情况,只要这个人不是杀手,那么就可以把这个强连通分量里所有人的身份得知。所以果断缩点。
那么就得到了一张 DAG。我们只需要将这张 DAG 中所有入度为 0 的点(也就是原先的一个强连通分量)询问即可得出所有人的身份。设入度为 0 的点有 \(k\) 个,那么只需要问 \(k\) 次即可。
但是考虑一种情况:已经得知其中 \(n-1\) 个人均为平民,那么排除法即可知道最后一个人是杀手。所以如果存在一个大小为 1 且没有入度的强连通分量,那么只需要问 \(k-1\) 次即可。
那么答案就是 \(1-\frac{k}{n}\)。特殊情况 \(k\) 要减一。
时间复杂度 \(O(n)\)。

代码

#include <stack>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=300010;
int head[N],dfn[N],low[N],deg[N],pos[N],U[N],V[N];
int n,m,tot,cnt,ans;
bool vis[N];
vector<int> scc[N];
stack<int> st;

struct edge
{
	int next,to;
}e[N];

void add(int from,int to)
{
	e[++tot].to=to;
	e[tot].next=head[from];
	head[from]=tot;
}

void tarjan(int x)
{
	dfn[x]=low[x]=++tot;
	st.push(x);
	vis[x]=1;
	for (int i=head[x];~i;i=e[i].next)
	{
		int v=e[i].to;
		if (!dfn[v])
		{
			tarjan(v);
			low[x]=min(low[x],low[v]);
		}
		else if (vis[v])
			low[x]=min(low[x],low[v]);
	}
	if (low[x]==dfn[x])
	{
		int y;
		cnt++;
		do {
			y=st.top(); st.pop();
			vis[y]=0; pos[y]=cnt;
			scc[cnt].push_back(y);
		} while (y!=x);
	}
}

int check()
{
	for (int i=1;i<=n;i++)
		if (!deg[i])
		{
			bool flag=1;
			for (int j=head[i];~j;j=e[j].next)
				if (deg[e[j].to]==1)
				{
					flag=0;
					break;
				}
			if (flag) return 1;
		}
	return 0;
}

int main()
{
	memset(head,-1,sizeof(head));
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
	{
		scanf("%d%d",&U[i],&V[i]);
		add(U[i],V[i]);
	}
	tot=0;
	for (int i=1;i<=n;i++)
		if (!dfn[i]) tarjan(i);
	for (int i=1;i<=m;i++)
		if (pos[U[i]]!=pos[V[i]]) deg[pos[V[i]]]++;
	for (int i=1;i<=cnt;i++)
		if (!deg[i]) ans++;
	memset(deg,0,sizeof(deg));
	for (int i=1;i<=m;i++)
		deg[V[i]]++;
	printf("%0.6lf",1.0-1.0*(ans-check())/n);
	return 0;
}

标签:cnt,include,游戏,int,杀手,tot,low,杀人,P4819
来源: https://www.cnblogs.com/stoorz/p/13095642.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有