题意...看了题解才知道 认识关系是可以传递的啊
注意一个坑人的特判
一开始看到这个题还以为是关于概率和期望的问题,,结果发现这题的概率就是个没有技术含量的东西,,假如警察一共只询问了x个人的话,那么安全的概率就是1-x/n,,所以说关键就是求出x的值;
我们发现如果将所有关系看作一棵树的话,那么我们只要调查树的根节点就可以了,也就是说我们的答案就是1-根节点数/节点总数;但是我们发现这个有向图并不是一棵树,而是有环存在的,这样我们就无法将图转换成一棵树,,这时我们可以考虑缩点,,因为如果关系构成环的话,那么我们调查环内的任何一个节点都可以将整个环调查出来,也就是说对于整个环,我们只需算作一次调查,所以我们可以将环用Tarjan算法缩成一个点,这样整个图就变成了一个有向无环图,即一棵树,然后我们将图遍历一遍,求出入度为1的节点(即根节点)个数,然后算出答案即可。
还需要注意一个问题,由于题目的关系,我们可以知道如果最后只剩一个点没有调查,那么可以直接确定这个点的身份,就不用再次调查一遍了。那么这个单点应该怎么确定呢?首先它的入度要为0,其次它的出边所连的点应该可以包含在其他子树中(也就是相连点的入度大于1),那么这个点就可以放到最后,先询问其他点,这样最后这个点的身份也就确定了。所以如果我们发现有这样的点的话,令根节点数减1就可以了。
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(int &x)
{
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const int N=100005;
const int M=300005;
struct Stack{
int s[N],p;
void clear(){ p=0; cl(s); }
void push(int x){ s[++p]=x; }
void pop(){ s[p--]=0; }
int top(){ return s[p]; }
bool empty(){ return p==0; }
}S;
struct edge{
int u,v; int next;
};
edge G[M];
int head[N],inum;
inline void add(int u,int v,int p)
{
G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
int cnt,tot[N];
int clk,pre[N],low[N],scc[N];
#define V G[p].v
inline void Tarjan(int u)
{
low[u]=pre[u]=++clk;
S.push(u);
for (int p=head[u];p;p=G[p].next)
if (!pre[V])
Tarjan(V),low[u]=min(low[u],low[V]);
else if (!scc[V])
low[u]=min(low[u],pre[V]);
if (low[u]==pre[u])
{
++cnt;
while (!S.empty())
{
int x=S.top(); S.pop();
scc[x]=cnt; tot[cnt]++;
if (x==u) break;
}
}
}
int vst[N],deg[N];
namespace Graph{
struct edge{
int u,v; int next;
}G[M];
int head[N],inum;
inline void add(int u,int v){
int p=++inum; G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}
inline bool Jud(int u){
for (int p=head[u];p;p=G[p].next)
if (deg[V]==1)
return 0;
return 1;
}
}
int n,m,ans;
int main()
{
int iu,iv;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n); read(m);
for (int i=1;i<=m;i++)
read(iu),read(iv),add(iu,iv,++inum);
for (int i=1;i<=n;i++)
if (!pre[i])
Tarjan(i);
for (int i=1;i<=n;i++)
{
int u=i;
for (int p=head[u];p;p=G[p].next)
if (scc[u]!=scc[V] && !vst[scc[V]])
vst[scc[V]]=1,Graph::add(scc[u],scc[V]),deg[scc[V]]++;
for (int p=head[u];p;p=G[p].next)
if (scc[u]!=scc[V])
vst[scc[V]]=0;
}
for (int i=1;i<=cnt;i++)
if (!deg[i])
ans++;
for (int i=1;i<=cnt;i++)
if (!deg[i] && tot[i]==1 && Graph::Jud(i))
{
ans--; break;
}
printf("%.6lf\n",1.0-(double)ans/n);
return 0;
}