zoukankan      html  css  js  c++  java
  • bzoj2438

    题解:

    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;
    }
  • 相关阅读:
    C++内置类型对象之间的转换
    快速排序
    面试题7:用两个栈实现队列
    面试题6:重建二叉树
    poj 3264(线段树)
    poj 3038
    poj 并查集
    poj 1270(toposort)
    poj 2503(字符串)
    poj 3687(拓扑排序)
  • 原文地址:https://www.cnblogs.com/xuanyiming/p/7732262.html
Copyright © 2011-2022 走看看