【并查集 / 图论】蓝桥云课 - 魔法大陆的城市群(求无向图连通块数量)题解

【并查集 / 图论】蓝桥云课 - 魔法大陆的城市群(求无向图连通块数量)题解

1. 题目概述

  • 题目大意 :给定 nnn 个城市和 mmm 条双向道路。如果两个城市之间可以通过道路直接或间接到达,则属于同一个"城市群"。求魔法大陆上一共有多少个城市群(即求无向图中的连通块数量)。
  • 数据规模 :2≤n≤1052 \le n \le 10^52≤n≤105,1≤m≤2×1051 \le m \le 2 \times 10^51≤m≤2×105

2. 解题思路

本题是经典的无向图连通块计数问题 。由于数据规模 nnn 达到了 10510^5105,使用 并查集(Disjoint Set Union, DSU) 是最简洁且高效的解法。

  1. 核心思想:

    • 初始时,将 nnn 个城市视为 nnn 个互相独立的城市群,设置答案计数器 ans = n。
    • 顺序读入每条双向道路 (u,v)(u, v)(u,v),利用并查集查找 uuu 和 vvv 的根节点:
      • 若根节点不同,说明这两个城市群之前不连通,通过当前道路合并两个集合,并将 ans 减 1。
      • 若根节点相同,说明它们早已连通,忽略该条边。
    • 处理完所有道路后,剩余的 ans 即为最终的城市群数量。
  2. 为什么选择并查集而非 DFS:

    • 无需显式建图:不需要构造邻接表保存边关系,边读入边处理,节省内存。
    • 防爆栈 :数据规模 n=105n=10^5n=105 时,若图退化为一条长链,DFS 递归层数过深易引发栈溢出(Segmentation Fault)。并查集配合路径压缩则非常稳定。

3. C++ 源码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 100005;
int parent[MAXN];

// 查找根节点(带路径压缩)
int find(int x) {
    if (parent[x] == x) return x;
    return parent[x] = find(parent[x]); // 路径压缩,扁平化树结构
}

int main() {
    // 优化标准输入输出流
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    if (!(cin >> n >> m)) return 0;

    // 1. 初始化:每个城市各自独立为一个集合
    for (int i = 1; i <= n; i++) {
        parent[i] = i;
    }

    int ans = n; // 初始连通块数量为 n

    // 2. 依次处理每条边
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        int rootU = find(u);
        int rootV = find(v);

        // 不属于同一连通块则进行合并,连通块总数 -1
        if (rootU != rootV) {
            parent[rootU] = rootV;
            ans--;
        }
    }

    // 3. 输出最终的连通块数量
    cout << ans << "\n";

    return 0;
}

4. 复杂度分析

  • 时间复杂度 :O(n+m⋅α(n))O(n + m \cdot \alpha(n))O(n+m⋅α(n))。其中 α\alphaα 为阿克曼函数的反函数,近乎于常数 O(1)O(1)O(1)。即使在最坏情况下,总运算次数也在 10510^5105 级别,运行时间不超过 20ms。
  • 空间复杂度 :O(n)O(n)O(n)。仅需开辟一个大小为 10510^5105 的 parent 父节点数组,内存消耗小于 1MB。
相关推荐
十二19 小时前
【洛谷题解】P1083 [NOIP 2012 提高组] 借教室(二分答案 + 差分)
数据结构·c++·算法·蓝桥杯
青少儿编程课堂2 天前
蓝桥杯青少组省考(11/9报名截止·11/22开考)+电子学会图形化考级+信息素养大赛:校园极速跑酷闯关解析
蓝桥杯·scratch·图形化编程·信息素养大赛·电子学会考级
Tairitsu_H5 天前
[C++高阶数据结构·图论下] 最短路径:为什么“挑最小的”一定正确?
数据结构·c++·图论
Tairitsu_H5 天前
[C++高阶数据结构·图论上] 最小生成树:为什么“选边”和“选点”是两条路?
数据结构·c++·图论·最小生成树
UIU1148 天前
P16237 [蓝桥杯 2026 省 B] 应急布线
数据结构·c++·算法·蓝桥杯
爱聊灵光的维C9 天前
C语言初阶:关于函数设计的详细讲解和注意事项
c语言·开发语言·青少年编程·蓝桥杯·学习方法
Mortalbreeze11 天前
0 - 1 BFS 算法详解:从基本原理到经典题目建模
数据结构·c++·算法·图论·宽度优先
一去不复返的通信er12 天前
力扣-图论-岛屿数量
算法·leetcode·图论
GG.WinGel12 天前
三元组中心问题
java·数据结构·算法·青少年编程·蓝桥杯
GG.WinGel13 天前
质数数目(蓝桥杯练习题)
java·数据结构·算法·青少年编程·蓝桥杯