POJ 2186 Popular Cows (强联通分量)

链接 :http://poj.org/problem?id=2186

一个联通分量里的所有的牛满足任何一个被其他牛认为是红人。强联通缩点之后 只需要找到一个且只有一个联通分量且它的出度为0 答案就是这个强联通分量点的个数。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <cmath>
#include <map>
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mem(a) memset(a,0,sizeof(a))
typedef long long ll;
const int N = 10005;
const int M = 50005;
const ll mod = 1000000007;

using namespace std;

int n, m, dfs_clock, scc_cnt;
int he[N], pre[N], low[N], scc[N];
stack <int> S;

struct C {
    int ne, to;
} e[M];

void add(int id, int x, int y) {
    e[id].to = y;
    e[id].ne = he[x];
    he[x] = id;
}

void dfs(int u) {

    pre[u] = low[u] = ++ dfs_clock;
    S.push(u);
    for(int i = he[u]; i != -1; i = e[i].ne) {

        int v = e[i].to;
        if(pre[v] == 0) {
            dfs(v);
            low[u] = min(low[u], low[v]);
        } else if(scc[v] == 0) {
            low[u] = min(low[u], pre[v]);
        }

    }

    if(low[u] == pre[u]) {
        scc_cnt ++;
        while(1) {
            int x = S.top(); S.pop();
            scc[x] = scc_cnt;
            if(x == u) break;
        }
    }

}

void find_scc() {
    mem(scc);
    mem(pre);
    dfs_clock = scc_cnt = 0;
    for(int i = 1; i <= n; i++) {
        if(pre[i] == 0) dfs(i);
    }
}

int out[N], v[N];

int main() {

    while(cin >> n >> m) {
        memset(he, -1, sizeof(he));
        for(int i = 1; i <= m; i++) {
            int x, y;
            scanf("%d%d", &x, &y);
            add(i, x, y);
        }

        find_scc();

        mem(v);
        for(int i = 1; i <= n; i++) {
            v[ scc[i] ]++;
        }
        //printf("%d\n", scc_cnt);
        int ans;
        for(int u = 1; u <= n; u++) {
            for(int i = he[u]; i != -1; i = e[i].ne) {
                int v = e[i].to;
                if(scc[u] != scc[v]) {
                    out[scc[u]] = 1;
                }
            }
        }

        int cnt = 0;
        for(int i = 1; i <= scc_cnt; i++) {
            if(out[i] == 0) {
                cnt++;
                ans = v[i];
            }
        }

        if(cnt == 1) {
            printf("%d\n", ans);
        } else puts("0");

    }

    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值