zoukankan      html  css  js  c++  java
  • BZOJ1051 [HAOI2006]受欢迎的牛 Tarjan 强连通缩点

    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ1051


    题意概括

      有n只牛,有m个羡慕关系。

      羡慕关系具有传递性。

      如果A羡慕B,B羡慕C,那么我们认为A也羡慕C。

      问有多少牛被所有其他牛羡慕。


    题解

      这次做这题我已经是第三遍了。

      USACO经典老题啊!(奶牛)

      POJ上面也有,叫popular cow。

      做法:

      先Tarjan强连通缩个点。

      然后,统计下入度。

      统计入度为0的点数。如果点数大于1,那么答案明显是0。

      如果点数是1,那么答案就是唯一的入度为0的点在缩点前点的个数。


    代码

    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    const int N=10000+5,M=50000+5;
    struct Gragh{
        int cnt,x[M],y[M],nxt[M],fst[N];
        void set(){
            cnt=0;
            memset(fst,0,sizeof fst);
        }
        void add(int a,int b){
            x[++cnt]=a,y[cnt]=b;
            nxt[cnt]=fst[a],fst[a]=cnt;
        }
    }g;
    int n,m;
    int dfn[N],low[N],st[N],time,ans,top,bh[N],cnt[N];
    bool inst[N],vis[N];
    void Tarjan_Prepare(){
        time=ans=top=0;
        memset(bh,0,sizeof bh);
        memset(st,0,sizeof st);
        memset(dfn,0,sizeof dfn);
        memset(low,0,sizeof low);
        memset(vis,0,sizeof vis);
        memset(inst,0,sizeof inst);
    }
    void Tarjan(int x){
        dfn[x]=low[x]=++time;
        vis[x]=inst[x]=1;
        st[++top]=x;
        for (int i=g.fst[x];i;i=g.nxt[i])
            if (!vis[g.y[i]]){
                Tarjan(g.y[i]);
                low[x]=min(low[x],low[g.y[i]]);
            }
            else if (inst[g.y[i]])
                low[x]=min(low[x],low[g.y[i]]);
        if (low[x]==dfn[x]){
            ans++;
            bh[st[top]]=ans;
            inst[st[top]]=0;
            while (st[top--]!=x){
                bh[st[top]]=ans;
                inst[st[top]]=0;
            }
        }
    }
    int main(){
        g.set();
        scanf("%d%d",&n,&m);
        for (int i=1,a,b;i<=m;i++){
            scanf("%d%d",&a,&b);
            g.add(a,b);
        }
        Tarjan_Prepare();
        for (int i=1;i<=n;i++)
            if (!vis[i])
                Tarjan(i);
        memset(cnt,0,sizeof cnt);
        for (int i=1;i<=m;i++)
            if (bh[g.x[i]]!=bh[g.y[i]])
                cnt[bh[g.x[i]]]++;
        int which=-1;
        for (int i=1;i<=ans;i++)
            if (cnt[i]==0){
                if (which!=-1){
                    printf("0");
                    return 0;
                }
                which=i;
            }
        int Ans=0;
        for (int i=1;i<=n;i++)
            if (bh[i]==which)
                Ans++;
        printf("%d",Ans);
        return 0;
    }
  • 相关阅读:
    两个有序数组,找第k小的数//未完
    top详解--查看cpu及内存使用情况
    查看IO情况
    hadoop常用的调优参数
    zookeeper 的 javaAPI
    MapReduce优化
    mySQL索引数据数据结构 B+ 树
    P2670 [NOIP2015 普及组] 扫雷游戏
    P1887 乘积最大3
    1299. 五指山
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ1051.html
Copyright © 2011-2022 走看看