ICode9

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

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

2020-05-14 18:03:46  阅读:308  来源: 互联网

标签:Tarjan 一个点 int 杀手 询问 入度 BZOJ2438 2011 define


点此看题面

大致题意: 一张有向图上有\(n\)个点,其中有一个“杀手”。你可以进行无限次操作(只要你没死),每次询问一个点,如果这个点是“杀手”,你就死了;否则,你会得知这个点通向的所有点是不是“杀手”。若每个点是“杀手”的概率相同,求你不会死的概率。

前言

挺水一道题,然而死在了几个特殊数据上,可见我考虑不周全,特判不到位。(突然有种写考试反思的感觉

以后差不多每天就安排做几道难题(训练思维、拓宽眼界)加几道这样的简单题(测智商下限)吧。

题意转化

显然,当你询问一个点,若它并非“杀手”,你就可以得知它直接通向的所有点是否为“杀手”。因而如果你继续询问它直接通向的点,肯定是安全的。

也就是说,当你询问一个点,你就相当于询问了这个点通向的所有点。

那么根据贪心思想,由于每个点作为“杀手”的概率相同,所以我们可以先对原图\(Tarjan\)缩点,然后只要询问入度为\(0\)的点即可。

然后答案就是\(1-\frac{需要询问点个数}n\)。

但还要注意,如果询问完其他所有入度为\(0\)的点,只剩下最后入度为\(0\)的点这一个点没被询问过,那我们就不需要询问这个点了。

我的判断方式是若一个点能直接通往的所有点在删去它们之间的边后入度都不为\(0\),就说明这个点可以不被询问。

可是,虽然想到了这个特判,我却错在了一整个强连通分量的情况上。。。(因为按我的判法这整个强连通分量被我判为不需要询问的)

然后我特判了强连通分量个数为\(1\),结果又错在\(n=1\)的特殊数据上。。。

得出结论,我就是个智障。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000000
#define M 3000000
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
#define Gmin(x,y) (x>(y)&&(x=(y)))
using namespace std;
int n,m,ee,lnk[N+5];struct edge {int to,nxt;}e[M+5];
class FastIO
{
	private:
		#define FS 100000
		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
		#define tn (x<<3)+(x<<1)
		#define D isdigit(c=tc())
		char c,*A,*B,FI[FS];
	public:
		I FastIO() {A=B=FI;}
		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
}F;
namespace Tarjan//Tarjan
{
	#define nadd(x,y) (ne[++nee].nxt=nlnk[x],++deg[ne[nlnk[x]=nee].to=y])
	int d,dfn[N+5],low[N+5],T,S[N+5],IS[N+5],cnt,p[N+5],nee,nlnk[N+5],deg[N+5];edge ne[M+5];
	I void dfs(CI x)//缩点
	{
		dfn[x]=low[x]=++d,IS[S[++T]=x]=1;for(RI i=lnk[x],y;i;i=e[i].nxt)
			dfn[y=e[i].to]?IS[y]&&Gmin(low[x],dfn[y]):(dfs(y),Gmin(low[x],low[y]));
		if(low[x]==dfn[x]) {p[x]=++cnt,IS[x]=0;W(S[T]^x) p[S[T]]=cnt,IS[S[T--]]=0;--T;}
	}
	I void Solve()//求解答案
	{
		RI i,j;for(i=1;i<=n;++i) for(j=lnk[i];j;j=e[j].nxt) p[i]^p[e[j].to]&&nadd(p[i],p[e[j].to]);//建新图
		RI t=0,f=0,g;for(i=1;i<=cnt;++i) if(!deg[i])//对于入度为0的点
		{
			for(++t,j=nlnk[i];j;j=ne[j].nxt) --deg[ne[j].to];//删边
			for(g=1,j=nlnk[i];j;j=ne[j].nxt) !deg[ne[j].to]&&(g=0);f|=g;//若所有点入度都不为0,说明无需询问
			for(j=nlnk[i];j;j=ne[j].nxt) ++deg[ne[j].to];//把边加回来
		}t==1&&n^1&&(f=0),printf("%.6lf",1-1.0*(t-f)/n);//特判一个SCC、n≠1的情况,输出答案
	}
}
int main()
{
	RI i,x,y;for(F.read(n),F.read(m),i=1;i<=m;++i) F.read(x),F.read(y),add(x,y);
	for(i=1;i<=n;++i) !Tarjan::dfn[i]&&(Tarjan::dfs(i),0);return Tarjan::Solve(),0;
}

标签:Tarjan,一个点,int,杀手,询问,入度,BZOJ2438,2011,define
来源: https://www.cnblogs.com/chenxiaoran666/p/BZOJ2438.html

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

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

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

ICode9版权所有