【连通图|强连通+缩点】POJ-2186 Popular Cows

19 篇文章 0 订阅
14 篇文章 0 订阅
Popular Cows
Time Limit: 2000MS Memory Limit: 65536K
   

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

Hint

Cow 3 is the only cow of high popularity. 
————————————————————————————————————————————————————————————————————————————————————————————————
题意:N个奶牛有M对仰慕关系,给出u、v表示u仰慕v,问有几头奶牛受到其余所有奶牛的仰慕。(仰慕关系具有传递性)
思路:每个强连通分量当中,结点两两可达,也就是说每个奶牛相互仰慕。这就是一个朋友圈。给每个朋友圈编号,将它们缩成一个点。缩点之后,就得到了若干个朋友圈。每个朋友圈就是一个强连通分量。
如果朋友圈a到朋友圈b之间有边,那么朋友圈a里面的所有奶牛都仰慕朋友圈b。
这个时候看这些点的出度。出度为0的点就是被所有奶牛仰慕的点。
但是如果出度为0的点超过1个,说明没有任何一个奶牛被所有其他奶牛仰慕。
代码如下:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stack>
#define Mem(f, x) memset(f, x, sizeof(f))
#define PB push_back
using namespace std;

const int N = 1e4+5, M = 5e4+5;;
int dfn[N], scc_id[N], head[N], out[N], line[M][2];
int deep, scc_cnt, tot, n, m;
stack <int> s;
struct Edge {
    int v, next;
    Edge(){}
    Edge(int _v, int _next):
        v(_v), next(_next){}
}e[M];

void __init__()
{
    for(int i = 0; i < n; i++) {
        out[i] = dfn[i] = scc_id[i] = 0;
        head[i] = -1;
    }
    tot = deep = scc_cnt = 0;
}

void add(int u, int v)
{
    e[tot] = Edge(v, head[u]);
    head[u] = tot++;
}

int dfs(int u)
{
    int lowu = dfn[u] = ++deep;
    s.push(u);
    for(int i = head[u]; ~i; i = e[i].next) {
        int v = e[i].v;
        if(!dfn[v]) {
            int lowv = dfs(v);
            lowu = min(lowu, lowv);
        }
        else if(!scc_id[v]) {
            lowu = min(lowu, dfn[v]);
        }
    }
    if(lowu == dfn[u]) {
        scc_cnt++;
        while(1) {
            int x = s.top(); s.pop();
            scc_id[x] = scc_cnt;
            if(x == u) break;
        }
    }
    return lowu;
}

int main()
{
#ifdef J_Sure
    freopen("000.in", "r", stdin);
    //freopen("999.out", "w", stdout);
#endif
    while(~scanf("%d%d", &n, &m)) {
        __init__();
        for(int i = 0; i < m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            u--; v--;
            line[i][0] = u; line[i][1] = v;
            add(u, v);
        }
        for(int i = 0; i < n; i++) {
            if(!dfn[i]) dfs(i);
        }
        //缩点:把scc_id所储存的强连通分量标号当作顶点
        for(int i = 0; i < m; i++) {
            int u = scc_id[line[i][0]], v = scc_id[line[i][1]];
            if(u != v) out[u]++;
        }
        //统计出度为0的点,多于1个说明不只一头牛是终点
        int god = 0, who;
        for(int i = 1; i <= scc_cnt; i++) {
            if(!out[i]) {
                god++;
                if(god > 1) break;
                who = i;
            }
        }
        int ans = 0;
        if(god == 1) {
            for(int i = 0; i < n; i++) {
                if(scc_id[i] == who) ans++;
            }
            printf("%d\n", ans);
        }
        else puts("0");
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值