zoukankan      html  css  js  c++  java
  • P4819 [中山市选]杀人游戏 Tarjan

    题意:

    (N)个人,他们通过(M)条单向的认识关系形成了一张图,其中有一个人是杀手,若遇到杀手则你会死亡,若遇到平民,ta会告诉你,ta认识的人中每个人的身份,求保证自身安全的情况下查到杀手的概率最大是多少?

    范围&性质:(1le Nle 10^5,qle Mle 3 imes 10^5)

    分析:

    什么情况下会遇到杀手,那就是查一个不清楚身份的人时(好像是一句废话

    所以只需要查找所有入度为0的点就可以了,但本题点数过大,直接(O(n^2))会被卡,那么我们考虑怎么优化,我们发现对于一个强联通分量,里面的点都是互相认识的,所以我们先缩点,对于入度为0的强连通分量查询

    tips:在实际情况中还可以利用排除法,所以当一个入度为0且大小为1的点,他的所有儿子入度都大于1,那么意味着这个点可以不用查,因为最后我们可以通过排除法确定他的身份

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
    	const int maxn = 1e5+5;
    	int n,m,cnt=0,top=0,scc=0,ans=0,tim=0;
    	int head[maxn],u[maxn],v[maxn],rd[maxn],cd[maxn],st[maxn];
    	int dfn[maxn],low[maxn],belong[maxn],pre[maxn];
    	bool ins[maxn],flag;
    	
    	vector<int> to[maxn];
    	map<int,bool> edge[maxn];
    	
    	struct Edge
    	{
    		int to,nxt;
    	}e[maxn<<2];
    	
    	void add(int u,int v)
    	{
    		e[++cnt].to=v;
    		e[cnt].nxt=head[u];
    		head[u]=cnt;
    	}
    	
    	void tarjan(int u)
    	{
    		dfn[u]=low[u]=++tim;
    		st[++top]=u;
    		ins[u]=true;
    		for(int i=0;i<to[u].size();i++)
    		{
    			int v=to[u][i];
    			if(!dfn[v])
    			{
    				tarjan(v);
    				low[u]=min(low[u],low[v]);
    			}
    			else if(ins[v]) low[u]=min(low[u],dfn[v]);
    		}
    		if(low[u]==dfn[u])
    		{
    			scc++;
    			do
    			{
    				int v=st[top];
    				ins[v]=false;
    				belong[v]=scc;
    			}
    			while(st[top--]!=u);
    		}
    	}
    	
    	void work()
    	{
    		int a,b;
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=m;i++)
    		{
    			scanf("%d%d",&a,&b);
    			to[a].push_back(b);
    		}
    		for(int i=1;i<=n;i++)
    		{
    			if(!dfn[i]) tarjan(i);
    		}
    		
    		for(int u=1;u<=n;u++)
    		{
    			for(int i=0;i<to[u].size();i++)
    			{
    				int v=to[u][i];
    				if(belong[u]!=belong[v]&&!edge[belong[u]][belong[v]])
    				{
    					add(belong[u],belong[v]);
    					edge[belong[u]][belong[v]]=true;
    					rd[belong[v]]++;
    					cd[belong[u]]++;
    				}
    			}
    			pre[belong[u]]++;
    		}
    		for(int i=1;i<=scc;i++)
    		{
    			if(rd[i]==0)
    			{
    				ans++;
    				if(pre[i]==1)
    				{
    					if(cd[i]==0) flag=true;
    					else
    					{
    						bool ok=false;
    						for(int j=head[i];j;j=e[j].nxt)
    						{
    							int v=e[j].to;
    							if(rd[v]<=1)
    							{
    								ok=true;
    								break;
    							}
    						}
    						if(!ok) flag=true;
    					}
    				}
    			}
    		}
    		if(flag) ans--;
    		printf("%.6lf
    ",1.0-(double)ans/(double)n);
    	}
    	
    } 
    
    int main()
    {
    	zzc::work();
    	return 0;
    }
    
  • 相关阅读:
    Android Studio如何设置代码自动提示
    Java中Map的用法详解
    Android 管理Activity中的fragments
    Android
    WebApp之Meta标签
    iOS中为网站添加图标到主屏幕以及增加启动画面
    HTML5添加 video 视频标签后仍然无法播放的解决方法 IIS添加MIEI类型
    WebApp之 apple-touch-icon
    Eclipse编辑器基本设置
    Redis监控方案
  • 原文地址:https://www.cnblogs.com/youth518/p/13689294.html
Copyright © 2011-2022 走看看