跳转至

受欢迎的牛

原题链接

题目描述

每一头牛的愿望就是变成一头最受欢迎的牛。

现在有 \(N\) 头牛,编号从 \(1\)\(N\),给你 \(M\) 对整数 \((A,B)\),表示牛 \(A\) 认为牛 \(B\) 受欢迎。

这种关系是具有传递性的,如果 \(A\) 认为 \(B\) 受欢迎,\(B\) 认为 \(C\) 受欢迎,那么牛 \(A\) 也认为牛 \(C\) 受欢迎。

你的任务是求出有多少头牛被除自己之外的所有牛认为是受欢迎的。


Tarjan

通过 tarjan 缩点之后,形成的 DAG,可以发现,当只存在一个终点(即出度为0)的点,才存在被所有牛欢迎的情况,否则,不存在被所有牛欢迎的牛。

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <bits/stdc++.h>
using namespace std;

const int N = 10010, M = 50010;

int n ,m;
int h[N], e[M], ne[M], idx;
int dfn[N], low[N], dfncnt, sc;
int dout[N], scc[N], sz[N];
bool stk[N];
stack<int> S;

// dfn[u]: dfs遍历到u的时间
// low[u]: 从u开始走所能遍历到的最小时间戳
// dfncnt: 时间戳
// sc: 强连通分量个数
// scc[u]: u点的强连通分量的编号
// sz[u]: 编号为u的强连通分量所包含的点的个数
// stk[u]: u点是否存在于栈中

void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

void tarjan(int u) {
    dfn[u] = low[u] = ++dfncnt;
    S.push(u);
    stk[u] = true;

    for (int i = h[u]; i != -1; i = ne[i]) {
        int j = e[i];
        if (!dfn[j]) {
            tarjan(j);
            low[u] = min(low[u], low[j]);
        } else if (stk[j]) low[u] = min(low[u], dfn[j]);
    }

    if (dfn[u] == low[u]) {
        int y;
        sc++;
        do {
            y = S.top();
            S.pop();
            stk[y] = false;
            scc[y] = sc;
            sz[sc]++;
        } while (y != u);
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);

    cin >> n >> m;
    memset(h, -1, sizeof h);
    while (m--) {
        int a, b;
        cin >> a >> b;
        add(a, b);
    }

    for (int i = 1; i <= n; i++)
        if (!dfn[i])
            tarjan(i);

    for (int i = 1; i <= n; i++)
        for (int j = h[i]; j != -1; j = ne[j]) {
            int k = e[j];
            int a = scc[i], b = scc[k];
            if (a != b) dout[a]++;
        }

    int zeros = 0, res = 0;
    for (int i = 1; i <= sc; i++) {
        if (!dout[i]) {
            zeros++;
            if (zeros > 1) {
                res = 0;
                break;
            }
            res += sz[i];
        }
    }

    cout << res << endl;

    return 0;
}
回到页面顶部