题解:

tarjan+概率

首先tarjan缩点

然后计算一个x,计算方法:

1.每当有一个强连通分量i的入度为0,那么x++

2.如果有一个强连通分量i,它的入度为0,且它连的每一条边只有他连,那么x-1

答案就是(n-x)/n

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5,M=3e5+5;
int dfn[N],num[N],low[N],x,y,an[N],cnt,fi[N];
int zz[M],ne[M],f[M],k,size[N],n,m,r[N],a[N],t,l;
int jb(int x,int y)
{
    zz[++k]=y;
    f[k]=x;
    ne[k]=fi[x];
    fi[x]=k;
}
int dfs(int u)
{
    dfn[u]=low[u]=++l;
    a[++t]=u;
    for(int i=fi[u];i;i=ne[i])
     if(!dfn[zz[i]])
      {
        dfs(zz[i]);
        low[u]=min(low[u],low[zz[i]]);
      }
    else if(!an[zz[i]])low[u]=min(low[u],dfn[zz[i]]);
    if(low[u]==dfn[u])
     {
         num[++cnt]=u;
        while(t)
         {
            an[a[t]]=cnt;
            size[cnt]++;
            if(a[t--]==u) break;
         }
     }
}
int pd(int x)
{
    int u=num[x];
    for(int i=fi[u];i;i=ne[i])
     if(r[an[zz[i]]]==1)return 0;
    return 1;
}
int main()
{
    scanf("%d%d",&n,&m);
    while (m--)
     {
        scanf("%d%d",&x,&y);
        jb(x,y);
      }
    for(int i=1;i<=n;i++)
     if(!dfn[i]) dfs(i);
    for(int i=1;i<=k;i++)
     if(an[f[i]]!=an[zz[i]]) r[an[zz[i]]]++;  
    int ans=0;
    for(int i=1;i<=cnt;i++) 
     if(!r[i]) ans++; 
    for(int i=1;i<=cnt;i++)
     if(size[i]==1&&!r[i]&&pd(i))
      {
        ans--;
        break;
      }  
    printf("%.6lf",(double)(n-ans)/n);
    return 0;
}

 

posted on 2017-10-25 20:42  宣毅鸣  阅读(126)  评论(0编辑  收藏