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;
}

 

posted @ 2017-08-16 16:37  zzd233  阅读(218)  评论(0编辑  收藏  举报