1 条题解

  • 0
    @ 2025-8-24 22:28:05

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar lzyqwq
    我永远喜欢数据结构。

    搬运于2025-08-24 22:28:05,当前版本为作者最后更新于2022-06-12 18:03:15,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    这题第一问很简单,就是用 Tarjan 算法求出强连通分量记录大小就行了.不会 Tarjan 的可以去看这题.

    第二问怎么处理呢?我们想,如果点 vv 没有入度,则不满足存在 uvu \rightarrow v;如果点 vv 没有出度,则不满足存在 vuv \rightarrow u.

    那么该选择入度为 00 的点(这里点指强连通分量,下同)还是出度为 00 的点呢?

    如果入度为 00 的点多于出度为 00 的点,那么满足出度为 00 的点都有到入度为 00 的点的出边之后,还要满足那些剩余的入度为 00 的点有入边.所以这种情况取入度为 00 的点.

    如果出度为 00 的点多于入度为 00 的点,那么满足入度为 00 的点都有从出度为 00 的点出发的入边之后,还要满足那些剩余的出度为 00 的点有出边.所以这种情况取出度为 00 的点.

    因此,我们取出度为 00 的点的个数与入度为 00 的点的个数的最大值即可.

    注意,如果图中只有一个强连通分量,输出 00(因为这个图本身就是强连通图).

    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    #define N 100005
    int cnt, sum, n, m, dfn[N], low[N], scc[N], sz[N], ans, p, q; 
    vector<int> g[N];
    stack<int> s;
    bool rd[N], cd[N], v[N];
    void tarjan(int x) {
        dfn[x] = low[x] = ++cnt;
        s.push(x);
        v[x] = 1;
        for (int i : g[x]) {
            if (!dfn[i]) {
                tarjan(i);
                low[x] = min(low[x], low[i]);
            } else if(v[i]) {
                low[x] = min(low[x], dfn[i]);
            }
        }
        if (dfn[x] == low[x]) {
            ++sum;
            while (1) {
                int k = s.top();
                s.pop();
                scc[k] = sum;
                v[k] = 0;
                sz[sum]++;
                if (x == k) {
                    break;
                }
            }
        }
    }
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1, u, v; i <= m; i++) {
            scanf("%d%d", &u, &v);
            g[u].push_back(v);
        }
        for (int i = 1; i <= n; i++) {
            if (!dfn[i]) {
                tarjan(i);
            }
        }
        for (int i = 1; i <= sum; i++) {
            ans = max(ans, sz[i]);
        }
        printf("%d\n", ans);
        if (sum == 1) {
            puts("0");
            return 0;
        }
        for (int i = 1; i <= n; i++) {
            for (int j : g[i]) {
                if (scc[i] != scc[j]) {
                    rd[scc[j]] = 1;
                    cd[scc[i]] = 1;
                }
            }
        }
        for (int i = 1; i <= sum; i++) {
            if (!rd[i]) {
                p++;
            }
            if (!cd[i]) {
                q++;
            }
        }
        printf("%d\n", max(p, q));
        return 0;
    }
    
    • 1

    信息

    ID
    6386
    时间
    1000ms
    内存
    128MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者