POJ 2186 Popular Cows - from lanshui_Yang

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
    题目大意:有一群奶牛,对于奶牛A,B,C,如果A仰慕B,B仰慕C,那么A仰慕C,即具有传递性。给你m对奶牛之间的爱慕关系,让你统计出被所有其他奶牛仰慕的奶牛的个数。
    解题思路:容易想到,在同一个强连通分量中的奶牛受到此强连通分量中其他所有奶牛的仰慕;如果一个强连通分量中的一头奶牛受到此强连通分量外的一头奶牛 Y 仰慕,那么此强连通分量中的所有奶牛都受到奶牛 Y 的仰慕;如果一个强连通分量中的一头奶牛 仰慕 此强连通分量外的一头奶牛 K , 则奶牛 K 受到此强连通分量中的所有奶牛的仰慕。下面具体说一下解题过程:先用tarjan缩点,然后统计出缩点后形成的新图中的出度为 0 的顶点个数sumj,如果sumj > 1 ,则答案是 0 ,即不存在符合条件的奶牛;否则,就 输出 出度为0的顶点所代表的的强连通分量中的奶牛个数。
    请看代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<vector>
#define me(a , b) memset(a , b , sizeof(a))
using namespace std ;
const int MAXN = 1e4 + 5;
struct Node
{
    int adj ;
    Node *next ;
}mem[MAXN *5] ;
Node *vert[MAXN] ;
int memp ;
int n , m ;
int dfn[MAXN] ;
int low[MAXN] ;
bool vis[MAXN] ;
bool inq[MAXN] ;  // 入栈标记
int stap[MAXN] ;  // 模拟栈
int d[MAXN] ;  // 统计每个强连通分量的入度
int id[MAXN] ;
int sum[MAXN] ;  // 记录每个强连通分量中的顶点数(即奶牛数)
int scnt ;   // 记录强连通分量个数
int top ;
int tmpdfn ;
int ans ;
void clr()
{
    me(vert , 0) ;
    me(dfn , 0) ;
    me(low , 0) ;
    me(vis , 0) ;
    me(stap , -1) ;
    me(inq , 0) ;
    me(d , 0) ;
    me(id , -1) ;
    me(sum , 0) ;
    top = -1 ;
    memp = 0 ;
    tmpdfn = 0 ;
    scnt = 0 ;
}
void tarjan(int u)
{
    vis[u] = 1 ;
    dfn[u] = low[u] = ++ tmpdfn ;
    stap[++ top] = u ;
    inq[u] = true ;
    Node *p = vert[u] ;
    while (p)
    {
        int v = p -> adj ;
        if(!vis[v])
        {
            tarjan(v) ;
            low[u] = min(low[u] , low[v]) ;
        }
        else if(inq[v])
        {
            low[u] = min(low[u] , dfn[v]) ;
        }
        p = p -> next ;
    }
    if(low[u] == dfn[u])
    {
        scnt ++ ;
        int tmp ;
        do
        {
            sum[scnt] ++ ;
            tmp = stap[top --] ;
            inq[tmp] = false ;
            id[tmp] = scnt ;
        }while (tmp != u) ;
    }
}
void init()
{
    clr() ;
    int i ;
    for(i = 0 ; i < m ; i ++)
    {
        int a , b ;
        scanf("%d%d" , &a , &b) ;
        Node *p ;
        p = &mem[memp ++] ;
        p -> adj = b ;
        p -> next = vert[a] ;
        vert[a] = p ;
    }
}
void solve()
{
    int i ;
    for(i = 1 ; i <= n ; i ++)
    {
        if(!vis[i])
        tarjan(i) ;
    }
    if(scnt == 1)  // 如果只有一个强连通分量,那么原图中的所有点均符合条件
    {
        ans = n ;
        return ;
    }
    Node *p ;
    for(i = 1 ; i <= n ; i ++)
    {
        p = vert[i] ;
        while (p)
        {
            int x , y ;
            x = id[i] ;
            y = id[p -> adj] ;
            if(x != y)
            {
                d[x] ++ ;
            }
            p = p -> next ;
        }
    }
    int sumj = 0 ;
    int j ;
    for(i = 1 ; i <= scnt ; i ++)  // 统计出度为0的顶点数
    {
        if(d[i] == 0)
        {
            j = i ;
            sumj ++ ;
        }
    }
    if(sumj > 1)
    {
        ans = 0 ;
    }
    else
    {
        ans = sum[j] ;
    }
}
int main()
{
    while (scanf("%d%d" , &n , &m) != EOF)
    {
        init() ;
        solve() ;
        printf("%d\n" , ans) ;
    }
    return 0 ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值