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

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

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。
相关推荐
h_a_o777oah7 天前
【图论】网络流:Dinic 算法模板实现原理及解题技巧
c++·算法·图论·acm·网络流·最小割·dinic算法
捷瑞电子工坊8 天前
嵌入式蓝桥杯从零点亮第一个LED
stm32·蓝桥杯·cubemx·嵌入式·led·ll·锁存
有点。9 天前
C++03阶段练习(练习题)
数据结构·算法·图论
-dzk-13 天前
【图论】LC 207.课程表
图论
wuyk55514 天前
18.Kruskal 算法:用最短的边连成一张网
开发语言·算法·图论
-dzk-14 天前
【图论】LC 994.腐烂的橘子
图论
-dzk-15 天前
【图论】LC 200.岛屿数量
深度优先·图论
Lyyaoo.16 天前
【图论】岛屿数量/腐烂的橘子/课程表/实现前缀树
图论
lvwangshu18 天前
图论:LCA、树的直径、树的重心、二分图与 Tarjan 缩点
算法·图论
aqiu11111118 天前
【数位 DP / 记忆化搜索】蓝桥云课 - 光轨区的 AI 数 题解
c++·算法·蓝桥杯·数位dp