并查集解题思路:CodeFancy 账号使用者最小数量

问题描述

想象学竞赛网站 CodeFancy 举办了 m 场比赛。你在 CodeFancy 上关注了 n 个账号,编号为 1∼n。你知道这 n 个账号分别参加了 m 场比赛中的哪些。但是你发现可能存在一个人使用多个账号的情况,你想知道这 n 个账号的使用者最少共有多少人。

具体地,账号和使用者的关系由两条规则限定:

  1. 一个人在一场比赛中至多使用一个账号。
  2. 一个账号的使用者只有恰好一个人。

输入格式

第一行两个正整数 n,m。

接下来 m 行,每行先输入一个正整数 k,表示参加这场比赛的账号数量;接下来输入 k 个正整数,表示参加这场比赛的账号编号。

输出格式

一行一个非负整数,表示最少的人数。

样例

样例 1 输入

5 3
2 1 2
3 2 3 4
4 4 5 1 2

样例 1 输出

4

样例 1 解释

一种合法的方案是,四个人使用的账号集合分别为:{1,3},{2},{4},{5}。

可以证明,不存在人数更少的合法方案。

解题思路

对于这道题目的解题思路,我们可以使用并查集(Disjoint Set)来解决。

首先,我们创建一个大小为 n 的并查集,每个元素初始时都是独立的根节点。然后,我们遍历每场比赛,将参加该比赛的账号进行合并操作。

具体步骤如下:

  1. 初始化并查集,每个账号编号对应一个独立的集合,即根节点为自身。
  2. 遍历每场比赛,对于每个比赛中的账号集合,将其中的账号进行合并操作。
  3. 遍历并查集,统计根节点的个数,即为使用者的最少人数。

C++ 代码实现

#include <iostream>
#include <vector>

using namespace std;

class DisjointSet {
public:
    vector<int> parent;

    DisjointSet(int n) {
        parent.resize(n + 1);
        for (int i = 1; i <= n; i++) {
            parent[i] = i;
        }
    }

    int find(int x) {
        if (x == parent[x]) {
            return x;
        }
        return parent[x] = find(parent[x]);
    }

    void unite(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX != rootY) {
            parent[rootY] = rootX;
        }
    }
};

int main() {
    int n, m;
    cin >> n >> m;

    DisjointSet dsu(n);

    for (int i = 0; i < m; i++) {
        int k;
        cin >> k;
        if (k > 0) {
            int prevAccount;
            cin >> prevAccount;
            for (int j = 1; j < k; j++) {
                int account;
                cin >> account;
                dsu.unite(prevAccount, account);
            }
        }
    }

    int count = 0;
    for (int i = 1; i <= n; i++) {
        if (dsu.find(i) == i) {
            count++;
        }
    }

    cout << count << endl;

    return 0;
}

希望这个思路能够帮助你解决问题!如果你有任何问题,请随时提问。

并查集解题思路:CodeFancy 账号使用者最小数量

原文地址: https://www.cveoy.top/t/topic/udH 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录