首页 > 其他分享 >洛谷 P4819 杀人游戏

洛谷 P4819 杀人游戏

时间:2024-09-03 08:56:27浏览次数:3  
标签:洛谷 int 杀手 top stk ++ low 杀人 P4819

洛谷 P4819 杀人游戏

题意

有 \(n\) 个人,他们之中有一个杀手。

每个人都有可能是杀手,并且概率相等。

你可以询问若干人。

若询问的人是杀手,你会被干掉。

若询问的人是平民,你会知道他认识的所有人的身份。

给出一张有向图表示这 \(n\) 个人的关系。

求出你活着知道杀手是谁的概率。

思路

先将原图强连通分量缩点,每个点内的人都互相认识。

形成一张 DAG 后,我们只需要问那些入度为 \(0\) 的点。

问了他们之后,他们后面的点的身份都已知道,不会再有被杀死的风险。

所以概率为 \(1-\frac{k}{n}\),\(k\) 为入度为 \(0\) 的点的个数,表示问这 \(k\) 个入度为 \(0\) 的点都问不到杀手的概率。

但这还不全对。

如果存在一个点大小为 \(1\),并且所有出边连的点入度都大于 \(1\),答案可变为 \(1-\frac{k-1}{n}\)。

因为如果存在这样的点,问过其他点后,他的所有出边连的点身份都清楚了。

如果有杀手,就不用问他了。

如果没有杀手,因为大小为 \(1\),所以杀手就是他,也不用问他了。

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
int tot, ver[N << 1], nxt[N << 1], head[N];
int n, m, dfn[N], low[N], in[N];
int cnt, sc, scc[N], stk[N], siz[N], top;
bool instk[N];
vector <int> E[N];
void add(int x, int y) {
	ver[++ tot] = y;
	nxt[tot] = head[x];
	head[x] = tot;
}
void tarjan(int x) {
	low[x] = dfn[x] = ++ cnt;
	stk[++ top] = x; instk[x] = 1;
	for (int i = head[x], y; i; i = nxt[i]) {
		y = ver[i]; 
		if (!dfn[y]) {
			tarjan(y);
			low[x] = min(low[x], low[y]);
		} else if (instk[y])
			low[x] = min(low[x], dfn[y]);
	}
	if (low[x] == dfn[x]) {
		sc ++;
		while (top && stk[top] != x) {
			scc[stk[top]] = sc;
			instk[stk[top]] = 0;
			siz[sc] ++;
			top --;
		}
		scc[stk[top]] = sc;
		instk[stk[top]] = 0;
		siz[sc] ++;
		top --;
	}
}
int main() {
	cin >> n >> m;
	for (int i = 1, u, v; i <= m; i ++) {
		cin >> u >> v;
		add(u, v);
	}
	for (int i = 1; i <= n; i ++) {
		if (dfn[i]) continue;
		tarjan(i);
	}
	for (int i = 1; i <= n; i ++) 
		for (int j = head[i]; j; j = nxt[j]) 
			if (scc[i] != scc[ver[j]]) {
				in[scc[ver[j]]] ++;
				E[scc[i]].push_back(scc[ver[j]]);
			}
				
	double ans = 1, N = n;
	int c = 0;
	bool flg = 0;
	for (int i = 1; i <= sc; i ++) {
		if (in[i]) continue;
		c ++;
		if (siz[c] > 1) continue;
		if (flg) continue;
		bool ok = 1;
		for (auto v : E[i]) 
			if (in[v] <= 1) ok = 0;
		if (ok) c --, flg = 1;
	}
	ans = 1.0 - 1.0 * c / N;
	cout << fixed << setprecision(6) << ans << "\n";
	return 0;
}

标签:洛谷,int,杀手,top,stk,++,low,杀人,P4819
From: https://www.cnblogs.com/maniubi/p/18393844

相关文章

  • 洛谷 P3225 矿场搭建
    洛谷P3225矿场搭建题意煤矿工地可以看成是由隧道连接挖煤点组成的无向图。为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处。于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之后,其他挖煤点的工人都有一条道路通向救援出口。请......
  • 洛谷 P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布
    题目大意小A和小B,要进行\(N\)次猜拳,每次按照一定周期出拳,胜负情况如下:求出小A和小B分别赢了几次。思路枚举\(N\)次猜拳,每次比较\(a[powera]\)与\(b[powerb]\)(poewra与powerb是a和b数组的索引,详见代码)。CODE#include<bits/stdc++.h>usingnamespacestd;in......
  • 题解:洛谷 P10996 【MX-J3-T3】Tuple
    原题链接介绍一种(也许是正解的)卡常做法先说总体思路:对于每个三元组\((x,y,z)\),若有一个\(w\)满足\((x,y,w),(x,z,w),(y,z,w)\)均存在,则找到了一个合法的四元组\((x,y,z,w)\)。\(20\\rm{Pts}\)做法如果暴力搜索,在遍历每一个三元组时,每一次都扫描所有的\(w\in[1,N]\)......
  • 题解:洛谷 P10497 [USACO03Open] Lost Cows
    原题链接思路+算法首先,考虑读入到\(a_i\)时,如果要得到此时的最优解(指所有牛的编号不重不漏地覆盖\([1,i]\)的所有编号),对于第\(i\)头奶牛,因为在它前面有\(a_i\)头奶牛的编号小于它,所以第\(i\)头奶牛的编号应当为\(a_i+1\)。如果有一头新的奶牛\(i+1\)加入到这个......
  • 题解:洛谷 P10878 [JRKSJ R9] 在相思树下 III
    原题链接解析在操作一时,最小值如果在最后一位,其无法更新任何数,会被删除;否则不在最后一位时一定会被其右侧更大的数更新。所以在操作一时,最小值一定会被更新掉。同理,在操作二时,最大值一定会被更新掉。由此,操作一决定了答案的下限,操作二决定了答案的上限。所以可以得出贪心策略......
  • 洛谷 P11012 颜料
    洛谷P11012颜料题意给出长度为\(n\)的序列\(a\)。定义一段区间\([l,r]\)的绚丽程度\(X_{l,r}\)为\(\sum_{i=1}^{W}\sum_{j=i+1}^W\min(c_i,c_j)\),其中\(W\)是值域,\(c_i\)表示\(a\)序列\([l,r]\)中\(i\)出现的次数,求绚丽程度至少为\(k\)的区间长度最小值。......
  • 洛谷 P11011 点的覆盖
    洛谷P11011点的覆盖题意给定一个四边平行于坐标轴的矩形\(A\),给定\(n\)个在矩形\(A\)内部(可能在边缘上)的点。求有多少个\(A\)的子矩形覆盖了所有\(n\)个点(允许在边缘上)。所有坐标都是整数。思路求出:\(X_1=\max_{i=1}^nx_i\),\(X_2=\min_{i=1}^nx_i\),\(Y_1=\max_......
  • 洛谷题单指南-常见优化技巧-P1950 长方形
    原题链接:https://www.luogu.com.cn/problem/P1950题意解读:在一张n*m个格子的纸上,从没有画过的格子中剪出长方形的方案数。解题思路:1、暴力做法枚举所有的子矩阵O(n^4),然后用二维前缀和计算子矩阵的和,通过和来判断子矩阵是否全部是'.'。2、优化做法针对每一行进行处理,计算包......
  • 洛谷 P2680 [NOIP2015 提高组] 运输计划
    洛谷P2680[NOIP2015提高组]运输计划题意给出一棵树和\(m\)条路径,可以选择一条边,把边权改为\(0\),求\(m\)条路经长度最大值的最小值。思路看到最大值最小,可以想到二分答案,答案具有单调性。考虑如何判定答案\(x\)是否可行。统计所有长度大于\(x\)的路径,统计它们共......
  • 洛谷P5322 [BJOI2019] 排兵布阵 题解
    代码#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongintdp[20001],a[101][101],s,n,m;signedmain(){ cin>>s>>n>>m; for(intj=1;j<=s;j++){ for(inti=1;i<=n;i++){ cin>>a[i][j]; } } for(inti=1;......