标签: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