天天看点

POJ - 2186  Popular Cows tarjain模板题

​​http://poj.org/problem?id=2186​​

首先求出所有的强连通分量,分好块。然后对于每一个强连通分量,都标记下他们的出度。那么只有出度是0 的块才有可能是答案,为什么呢?因为既然你有了出度,那么就是指向了另外一个块,那么你就不能指望那个块也指向你了,因为这样会形成环,所以肯定有一个块的cow不支持你,所以你这个块就不会是popular cow

那么就有两种情况,

①、出度是0的块的个数是1个,那么就是唯一的答案。

②、出度是0的快的个数有多个,那么答案是0, 因为至少也有一个块不支持你。

不会存在出度为0的个数是0这样的,起码都会有一个块出度是0.

记得清空各种数组。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;


#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <bitset>
const int maxn = 1e5 + 20;
struct Edge {
    int u, v, w, tonext;
}e[maxn * 2];
int first[maxn], num;
void addEdge(int u, int v) {
    ++num;
    e[num].u = u, e[num].v = v;
    e[num].tonext = first[u];
    first[u] = num;
}
int DFN[maxn], low[maxn], st[maxn], top, when, vis[maxn];
int id[maxn], toSelId, out[maxn], sum[maxn];
void tarjan(int cur, int fa) {
    DFN[cur] = low[cur] = ++when; // 时间戳
    st[++top] = cur; //进栈
    vis[cur] = true;
    for (int i = first[cur]; i; i = e[i].tonext) {
        int v = e[i].v;
        if (!DFN[v]) { //没访问过
            tarjan(v, cur);
            low[cur] = min(low[cur], low[v]);
        } else if (vis[v]) { // 访问过,而且还在栈里
            low[cur] = min(low[cur], DFN[v]);
        }
    }
    if (low[cur] == DFN[cur]) { //这个是强连通分量的根节点。
        ++toSelId;
        do {
            id[st[top]] = toSelId;
            sum[toSelId]++;
//            printf("%d ", st[top]);
            vis[st[top]] = false;
            top--;
        } while (cur != st[top + 1]);
//        printf("\n");
    }
}
void sloveTarjan(int n) { //防止开始枚举的节点没有出边,暴力枚举每一个节点
    memset(low, 0, sizeof low);
    memset(DFN, 0, sizeof DFN);
    memset(vis, 0, sizeof vis);
    memset(id, 0, sizeof id);
    memset(out, 0, sizeof out);
    memset(sum, 0, sizeof sum);
    top = when = toSelId = 0;
    for (int i = 1; i <= n; ++i) {
        if (!DFN[i]) {
            tarjan(i, i);
        }
    }
}
int n, m;
void work() {
//    int n, m;
//    scanf("%d%d", &n, &m);
    num = 0;
    memset(first, 0, sizeof first);
    for (int i = 1; i <= m; ++i) {
        int u, v;
        scanf("%d%d", &u, &v);
        addEdge(u, v);
    }
    sloveTarjan(n);
    for (int i = 1; i <= n; ++i) {
        for (int j = first[i]; j; j = e[j].tonext) {
            int v = e[j].v;
            if (id[i] == id[v]) continue;
            out[id[i]]++;
        }
    }
    int has = 0;
    int ans;
    for (int i = 1; i <= toSelId; ++i) {
        if (out[i] == 0) {
            has++;
            ans = i;
        }
    }
    if (has >= 2) {
        printf("0\n");
//        cout << 0 << endl;
        return;
    }
    printf("%d\n", sum[ans]);
//    cout << sum[ans] << endl;
}
int main() {
#ifdef local
    freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
    while (scanf("%d%d", &n, &m) != EOF) work();
    return 0;
}