标签:use 小数 最大 enter lang 强连通分量 eof mst txt
5 4
1 2
1 3
1 4
1 5
0.800000
警察只需要查证 1。假如1是杀手,警察就会被杀。假如 1不是杀手,他会告诉警察 2,3,4,5 谁是杀手。而 1 是杀手的概率是 0.2,所以能知道谁是杀手但没被杀的概率是0.8。对于 100%的数据有 1≤N ≤ 10 0000,0≤M ≤ 30 0000
Tarjan缩点后求强连通,有x个入度为0的点,则需要调查x次,则最后安全几率为1-x/n。
但这样不完全对,存在一种情况,当警察调查完x-1个人之后,他可以直接确定最后一个人是不是罪犯。这样安全的几率为1-(x-1)/n。而其充分条件为该入度为0的强连通分量,其相连的其他强连通分量入度大于1,。
#include <bits/stdc++.h> #define maxn 200000 using namespace std; int ind[maxn],low[maxn],dfn[maxn],in[maxn],out[maxn],tot,cnt; bool vis[maxn]; vector<int> a[maxn]; stack<int> s; struct Edge { int v,next; }; struct M { int head[maxn]; Edge edge[maxn*3]; int cnt; void init() { memset(head,-1, sizeof(head)); cnt=0; } void addedge(int u,int v) { edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt++; } }Mp; void Tarjan(int num) { vis[num]=true; low[num]=dfn[num]=++tot; s.push(num); for(int i=Mp.head[num];i!=-1;i=Mp.edge[i].next) { int v=Mp.edge[i].v; if(!dfn[v]) { Tarjan(v); low[num]=min(low[num],low[v]); } else if(vis[v]) { low[num]=min(low[num],dfn[v]); } } if(dfn[num]==low[num]) { ++cnt; while(true) { int now=s.top(); a[cnt].push_back(now); s.pop(); vis[now]=false; ind[now]=cnt; if(now==num) break; } } } int main() { //freopen("in.txt","r",stdin); int n,m,u,v; scanf("%d%d",&n,&m); Mp.init(); for(int i=1;i<=m;i++) { scanf("%d%d",&u,&v); Mp.addedge(u,v); } for(int i=1;i<=n;i++) { if(!dfn[i]) Tarjan(i); } for(int i=1;i<=n;i++) { for(int j=Mp.head[i];j!=-1;j=Mp.edge[j].next) { int v=Mp.edge[j].v; if(ind[v]!=ind[i]) { in[ind[v]]++; out[ind[i]]++; } } } int sum=0; for(int i=1;i<=cnt;i++) { if(in[i]==0) sum++; } double ans; for(int i=1;i<=cnt;i++) { if(in[i]==0&&a[i].size()==1) { int u=a[i][0]; bool f=false; for(int j=Mp.head[u];j!=-1;j=Mp.edge[j].next) { int v=Mp.edge[j].v; if(in[ind[v]]<=1) f=true; } if(f==false) { sum--; break; } } } ans=1-1.0*sum/n; printf("%.6lf\n",ans); }
标签:use 小数 最大 enter lang 强连通分量 eof mst txt
原文地址:https://www.cnblogs.com/zyf3855923/p/9678251.html