P4819 [中山市选] 杀人游戏

题目大意

详细题目传送门
给出一个有向图,点有黑白颜色,且只有一个黑点。如果选择一个点 u 可以知道相邻的点的所有颜色。求在不选择黑点后能知道黑点在哪个点上的概率 p

n105,m3105

思路

首先发现对于一个强联通分量,只要不访问到黑点那么就可以知道这个强联通分量里面的所有点的颜色。所以就先缩点,转成一个 DAG。在转成 DAG 后发现访问所有入度为 0 的点就可以知道原图所有点的颜色。那么概率就是 1cn,其中 c 表示为入度为 0 的强联通分量数量。

感觉就做完了,可是交上去发现是 30 分。发现不一定要访问所有入度为 0 的点,如果假设不访问一些入度为 0 的强联通也可以知道整张图的颜色的话那就没必要选。然后发现这个不选的强联通分量包含的个数大于 1 的话就一定不行,因为入度是 0 所以里面的点只能由这个强联通分量里面的点自己访问。那么如果这个强联通分量所连接的其他强联通分量只能由它转移也不行,即出边的强联通分量入度为 1。然后发现这个不选的强联通分量只能存在一个,因为如果有 2 个不选的话则这两个之间也是无法确定有没有凶手的,所以无法判断。

总结一下,就是在缩点后,求出 c 来判断是否存在一个入度为 1 的强联通分量满足:

  1. 大小为 1
  2. 没有出边的强联通分量度数大于 1

如果存在那么答案变为 1c1n

代码

#include<bits/stdc++.h>
#define rep(i,a,b) for(register ll i=(a);i<=(b);++i)
#define endl '\n'
using namespace std;
typedef long long ll;
const ll MAXN=1e5+5;
const ll MAXM=3e5+5;
ll n,m;
vector<ll>adj[MAXN];
ll pre[MAXN],low[MAXN],scc[MAXN],ts,sci;
stack<ll>ins;
void dfs(ll u){
    pre[u]=low[u]=++ts;
    ins.push(u);
    for(auto v:adj[u]){
        if(!pre[v]){
            dfs(v);
            low[u]=min(low[u],low[v]);
        }else if(!scc[v]){
            low[u]=min(low[u],pre[v]);
        }
    }
    if(pre[u]==low[u]){
        ++sci;
        while(true){
            ll tp=ins.top();
            ins.pop();
            scc[tp]=sci;
            if(tp==u){
                break;
            }
        }
    }
}
vector<ll>g[MAXN];
set<pair<ll,ll>>se;
ll ind[MAXN],sz[MAXN];
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>n>>m;
	rep(i,1,m){
	    ll u,v;
	    cin>>u>>v;
	    adj[u].push_back(v);
	}
	rep(i,1,n){
	    if(!pre[i]){
	        dfs(i);
	    }
	}
	rep(i,1,n){
	    sz[scc[i]]++;
	}
	rep(u,1,n){
	    for(auto v:adj[u]){
	        if(scc[v]!=scc[u]&&!se.count({scc[u],scc[v]})){
	            ind[scc[v]]++;
	            se.insert({scc[u],scc[v]});
	            g[scc[u]].push_back(scc[v]);
	        }
	    }
	}
	ll val=0,pc=0;
	rep(i,1,sci){
	    if(ind[i]==0){
	        val++;
	        if(!pc&&sz[i]==1){
	            bool gd=true;
	            for(auto v:g[i]){
	                if(ind[v]==1){
	                    gd=false;
	                    break;
	                }
	            }
	            if(gd){
	                pc=1;
	            }
	        }
	    }
	}
	printf("%0.6lf\n",1-1.0*((val-pc)*1.0/n));
	return 0;
}
posted @   tanghg  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示