现在的位置: 首页 > 综合 > 正文

POJ 2186 Popular Cows – from lanshui_Yang

2019年01月08日 ⁄ 综合 ⁄ 共 2458字 ⁄ 字号 评论关闭

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

抱歉!评论已关闭.