POJ 2186 Popular Cows

次元传送门

题意:
拿样例输入说吧

3 3
1 2
2 1
2 3

Line1是n和m,分别是点数和边数
下面是m对数,每对数x y表示:
x牛觉得y牛比较牛逼
那么上面的输入可以翻译成

有3只牛和3个输入
1觉得2比较牛逼
2觉得1比较牛逼
2觉得3比较牛逼

现在我们定义牛逼是具有传递性的,即
如果a觉得b比较牛逼,而b又觉得c比较牛逼,那么a也会觉得c比较牛逼
那么上面的样例其实就是一个有向图,并且有环
所以1和2都觉得3比较牛逼

而题目要求你统计一下一共有几只牛逼至极的牛,牛逼至极是这样定义的:所有其他的牛都觉得它很牛逼,那么该牛就是牛逼至极的

分析:
Tarjan找强连通分量并缩点,之后统计出度
后略

代码实现

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=50000;
int n,m,hd[maxn],nt[maxn],to[maxn],map[maxn],dfn[maxn],low[maxn],st[maxn],in[maxn],du[maxn],p,c,cnt,tot,ans;
inline void addedge(int x,int y){
    nt[cnt]=hd[x];
    to[cnt]=y;
    hd[x]=cnt++;
}
void Tarjan(int u){
    dfn[u]=low[u]=++tot;
    st[p++]=u,in[u]=1;
    for(int i=hd[u];~i;i=nt[i])
        if(!dfn[to[i]]) Tarjan(to[i]),low[u]=min(low[u],low[to[i]]);
        else if(in[to[i]])  low[u]=min(low[u],dfn[to[i]]);
    if(low[u]==dfn[u]){
        ++c;int t;
        do{
            t=st[--p],in[t]=0,map[t]=c;
        }while(t!=u);
    }
}
int main(void){
    while(scanf("%d%d",&n,&m)!=EOF){
        cnt=tot=ans=p=c=0;
        memset(hd,-1,sizeof(hd));
        memset(dfn,0,sizeof(dfn));
        memset(in,0,sizeof(in));
        memset(du,0,sizeof(du));
        for(int i=0,x,y;i<m;i++)
            scanf("%d%d",&x,&y),addedge(x,y);
        for(int i=1;i<=n;i++)
            if(!dfn[i]) Tarjan(i);
        for(int i=1;i<=n;i++)
            for(int j=hd[i];~j;j=nt[j])
                if(map[i]!=map[to[j]])  du[map[i]]++;
        int sum=0,t;
        for(int i=1;i<=c;i++)
            if(!du[i])  sum++,t=i;
        if(sum==1)
            for(int i=1;i<=n;i++)
                ans+=map[i]==t;
        printf("%d\n",ans); 
    }

    return 0;
}

By YOUSIKI

你可能感兴趣的:(POJ 2186 Popular Cows)