poj 2186 Popular Cows(强连通分量)

题目:http://poj.org/problem?id=2186

Popular Cows
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 27673 Accepted: 11139

Description

Every cow's dream is to become the most popular cow in the herd. In a herd of N (1 <= N <= 10,000) cows, you are given up to M (1 <= M <= 50,000) ordered pairs of the form (A, B) that tell you that cow A thinks that cow B is popular. Since popularity is transitive, if A thinks B is popular and B thinks C is popular, then A will also think that C is
popular, even if this is not explicitly specified by an ordered pair in the input. Your task is to compute the number of cows that are considered popular by every other cow.

Input

* Line 1: Two space-separated integers, N and M

* Lines 2..1+M: Two space-separated numbers A and B, meaning that A thinks B is popular.

Output

* Line 1: A single integer that is the number of cows who are considered popular by every other cow.

Sample Input

3 3
1 2
2 1
2 3

Sample Output

1
分析:
题目大意:如果A牛崇拜B牛,B牛崇拜C牛,则A牛也崇拜C牛。寻找有多少头牛它被所有的其他的牛崇拜。
关于强连通图:如果有向图G的任何两顶点都互相可达,则称图G是强连通图,如果有向图G存在两顶点u和v,使得u不能到达v或者v不能到达u,则称图G是非强连通图。
关于强连通分量的tarjan算法可以阅读博客: http://blog.csdn.net/thearcticocean/article/details/48398575
在有向无环图中有这样的点很特殊:outdegree=0 和 indegree=0的点。尝试将强连通分量压缩,通过缩点把杂乱的有向图变成一幅有向无环图,出度为0的点个数设为k,如果k=1那么就表明整个图是连通的,结果就是压缩点的个数,k>1则表明图不是连通的,结果是0。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M=5e4+10,N=1e4+10;
int head[N],ed;
struct node{
    int to,next;
}edge[M];
int sta[N],vis[N],low[N],dfn[N],out[N],top;
void init(){
    ed=0;
    memset(head,-1,sizeof(head));
    memset(edge,0,sizeof(edge));
    memset(out,0,sizeof(out));
    memset(sta,0,sizeof(sta));
}
void addedge(int a,int b){
    edge[ed].to=b;
    edge[ed].next=head[a];
    head[a]=ed++;
}
void tarbfs(int k,int cnt,int &num){
    vis[k]=1;
    low[k]=cnt;
    dfn[k]=cnt;
    sta[top++]=k;
    for(int i=head[k];i>-1;i=edge[i].next){
        if(vis[edge[i].to]==0) tarbfs(edge[i].to,++cnt,num);
        if(vis[edge[i].to]==1) low[k]=min(low[k],low[edge[i].to]);
    }
    if(dfn[k]==low[k]){
        ++num;
        while(top>0&&sta[top]!=k){
            top--;
            low[sta[top]]=num;
            vis[sta[top]]=2;
        }
    }
}
int tarjan(int n){
    int num=0,cnt=1;
    top=0;
    memset(vis,0,sizeof(vis));
    memset(low,0,sizeof(low));
    for(int i=1;i<=n;i++){
        if(vis[i]==0) tarbfs(i,cnt,num);
    }
    return num;
}

int main()
{
    //freopen("cin.txt","r",stdin);
    int n,m;
    while(cin>>n>>m){
        int a,b;
        init();
        for(int i=0;i<m;i++){
            scanf("%d%d",&a,&b);
            addedge(a,b);
        }
        int num=tarjan(n); 
        for(int i=1;i<=n;i++){
            for(int j=head[i];j>-1;j=edge[j].next){
                if(low[i]!=low[edge[j].to]) out[low[i]]++;
            }
        }
        int sum=0,x;
        for(int i=1;i<=num;i++){
            if(out[i]==0){  sum++; x=i;  }
        }
        if(sum==1){
            sum=0;
            for(int i=1;i<=n;i++){
                if(low[i]==x) sum++;
            }
            printf("%d\n",sum);
        }
        else puts("0");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值