洛谷P2835 刻录光盘 题解 点的度数+并查集

题目链接:https://www.luogu.com.cn/problem/P2835

解题思路:

如果A愿意借给B,则B的入度加一。

然后计算一下有多少个点的入度为0,这些是我们需要分配光盘的。

但是可能存在强联通分量,这种情况下,一个强联通分量里没有入读为0的点,但是我需要制定以下这个点。

所以我用 并查集 来维护,如果A愿意借给B,则A、B属于同一个集合。

首先计算有多少入度为0的点,假设有 \(cnt_1\) 个,找到这些点的同时将它们所属的集合标记为访问过。

然后计算有多少个没有被标记过的集合,假设这个数量为 \(cnt_2\)

则最终答案为: \(cnt_1 + cnt_2\)

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 220;
int n, d[maxn], f[maxn], a, cnt;
bool vis[maxn];
void init() {
    for (int i = 1; i <= n; i ++) f[i] = i;
}
int Find(int x) {
    return x == f[x] ? x : f[x] = Find(f[x]);
}
void Union(int x, int y) {
    int a = Find(x), b = Find(y);
    f[a] = f[b] = f[x] = f[y] = min(a, b);
}
int main() {
    cin >> n;
    init();
    for (int i = 1; i <= n; i ++) {
        while ((cin >> a) && a) {
            d[a] ++;
            Union(i, a);
        }
    }
    for (int i = 1; i <= n; i ++) if (!d[i]) { vis[Find(i)] = true; cnt ++; }
    for (int i = 1; i <= n; i ++) if (!vis[Find(i)]) { vis[Find(i)] = true; cnt ++; }
    cout << cnt << endl;
    return 0;
}
posted @ 2020-02-26 21:05  quanjun  阅读(242)  评论(0编辑  收藏  举报