[特殊字符] 蓝桥杯 Java B 组 之最小生成树(Prim、Kruskal) 并查集应用

news/2025/2/26 5:20:57

Day 3:最小生成树(Prim、Kruskal) & 并查集应用


📖 一、最小生成树(MST)简介

最小生成树(Minimum Spanning Tree, MST) 是一个 无向连通图最小代价子图,它包含 所有节点,且边的权重总和最小。

📌 最小生成树的性质

  1. 连通性:必须包含所有节点,且保证是连通的。
  2. 边数 = 节点数 - 1:MST 的边数始终是 V - 1V 是顶点数)。
  3. 权值最小:MST 的边权和最小。

📌 最小生成树的常见算法

算法核心思想时间复杂度
Kruskal贪心 + 并查集,按 边权 递增排序,逐步合并连通分量O(E log E)(边排序)
Prim贪心 + 最小堆,按 最小权重 逐步扩展 MSTO(E log V)(优先队列优化)

Kruskal 适用于稀疏图,Prim 适用于稠密图


📖 二、Kruskal 算法(贪心 + 并查集)

适用范围

  • 边稀疏的图(E 边较少)。
  • 适用于 离散集问题(如岛屿连通、网络电缆)。

🔹 1. 题目:连接所有城市的最低成本(Leetcode 1135)

题目描述: 给定 n 个城市,connections[i] = (u, v, cost) 表示 u-v 之间有条代价 cost 的边。找到最小代价的连接方案,使得所有城市连通,否则返回 -1

示例

输入: n = 3, connections = [[1,2,5],[1,3,6],[2,3,2]]
输出: 7 (选 [1,2] 和 [2,3])

🔹 2. 思路

  1. 贪心 + Kruskal 算法
    • 按边权排序(从小到大)。
    • 使用并查集(Union-Find) 逐步合并两个城市(避免形成环)。
    • n-1 条边后停止,若无法连通所有城市,则返回 -1

🔹 3. 代码实现(Kruskal)

import java.util.*;

public class KruskalMST {
    static class UnionFind {
        int[] parent, rank;
        
        public UnionFind(int n) {
            parent = new int[n + 1];
            rank = new int[n + 1];
            for (int i = 0; i <= n; i++) parent[i] = i;
        }

        public int find(int x) {
            if (x != parent[x]) parent[x] = find(parent[x]); // 路径压缩
            return parent[x];
        }

        public boolean union(int x, int y) {
            int rootX = find(x), rootY = find(y);
            if (rootX == rootY) return false; // 已经连通
            if (rank[rootX] > rank[rootY]) parent[rootY] = rootX;
            else if (rank[rootX] < rank[rootY]) parent[rootX] = rootY;
            else {
                parent[rootY] = rootX;
                rank[rootX]++;
            }
            return true;
        }
    }

    public int minCostToConnectCities(int n, int[][] connections) {
        Arrays.sort(connections, Comparator.comparingInt(a -> a[2])); // 按边权排序
        UnionFind uf = new UnionFind(n);
        int totalCost = 0, edgesUsed = 0;

        for (int[] conn : connections) {
            if (uf.union(conn[0], conn[1])) { // 连接成功
                totalCost += conn[2];
                edgesUsed++;
                if (edgesUsed == n - 1) break; // 最小生成树完成
            }
        }

        return edgesUsed == n - 1 ? totalCost : -1; // 判断是否连通
    }

    public static void main(String[] args) {
        KruskalMST solution = new KruskalMST();
        int[][] connections = {{1,2,5}, {1,3,6}, {2,3,2}};
        int n = 3;
        System.out.println(solution.minCostToConnectCities(n, connections)); // 输出 7
    }
}

🔹 4. 代码讲解

  1. 并查集(Union-Find)
    • find(x): 查找根节点(带路径压缩)。
    • union(x, y): 合并两个集合(按秩合并)。
  2. Kruskal 算法
    • 排序:按边权递增排序。
    • 遍历边:检查 u-v 是否已经连通,若未连通,则加入 MST。
    • 判断最终连通性:若选出的边数为 n-1,返回总代价,否则返回 -1

✅ 时间复杂度O(E log E)(排序 + 并查集)


📖 三、Prim 算法(贪心 + 最小堆)

适用范围

  • 边稠密的图(E 边较多)。
  • 适用于 邻接矩阵/邻接表存储

🔹 1. 代码实现(Prim)

import java.util.*;

public class PrimMST {
    public int minCostToConnectCities(int n, int[][] connections) {
        Map<Integer, List<int[]>> graph = new HashMap<>();
        for (int[] edge : connections) {
            graph.putIfAbsent(edge[0], new ArrayList<>());
            graph.putIfAbsent(edge[1], new ArrayList<>());
            graph.get(edge[0]).add(new int[]{edge[1], edge[2]});
            graph.get(edge[1]).add(new int[]{edge[0], edge[2]});
        }

        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
        pq.offer(new int[]{1, 0}); // 从城市 1 开始
        Set<Integer> visited = new HashSet<>();
        int totalCost = 0;

        while (!pq.isEmpty() && visited.size() < n) {
            int[] cur = pq.poll();
            int city = cur[0], cost = cur[1];

            if (visited.contains(city)) continue; // 已访问
            visited.add(city);
            totalCost += cost;

            for (int[] neighbor : graph.getOrDefault(city, new ArrayList<>())) {
                if (!visited.contains(neighbor[0])) {
                    pq.offer(neighbor);
                }
            }
        }

        return visited.size() == n ? totalCost : -1;
    }

    public static void main(String[] args) {
        PrimMST solution = new PrimMST();
        int[][] connections = {{1,2,5}, {1,3,6}, {2,3,2}};
        int n = 3;
        System.out.println(solution.minCostToConnectCities(n, connections)); // 输出 7
    }
}

📖 四、Kruskal vs Prim

算法核心数据结构适用场景时间复杂度
Kruskal并查集稀疏图(边少)O(E log E)
Prim最小堆(优先队列)稠密图(边多)O(E log V)

📖 五、总结

🎯 掌握 Kruskal(贪心 + 并查集),适用于离散集合最小代价连接问题
🎯 掌握 Prim(贪心 + 最小堆),适用于稠密图的最小生成树问题
🎯 最小生成树的应用

  • 网络连接(最小代价连通所有城市)
  • 电网铺设(最少电缆铺设)
  • 地图导航(最短成本的道路规划)


http://www.niftyadmin.cn/n/5868023.html

相关文章

django 的值有正确的格式 (YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]) 但它是一个错误的日期/时间‘

好的&#xff0c;我将根据你的要求来回答关于Django中日期时间格式的问题。 报错问题解释 在Django中&#xff0c;如果你在处理日期时间字段时遇到了错误&#xff0c;通常是因为你尝试将一个不符合Django期望格式的字符串或值赋给日期时间字段。Django的日期时间字段期望的格式…

rust安装教程以及git连接到远程仓库

1.官方网站下载rustup-init程序 链接: rust-lang 从这里可以获取到rust的下载程序,这个下载程序会帮助你下载visual-studio的安装包从而获取相关的编译环境。 tips:无需再下载visual_studio 2确认安装所需要的框架&#xff0c;SKD工具 安装完毕之后可以检查一下 rustc --ve…

Grafana使用日志4--直接对接Zabbix数据库的一些注意点

背景 之前zabbix有一个需求是监控每一笔交易的耗时&#xff0c;即结束时间-开始时间&#xff0c;现在由于业务需求&#xff0c;需要在Grafana中统计所有交易时间的占比&#xff0c;分组并展示 但是接入的zabbix插件并不支持该功能&#xff0c;zabbix插件只能够查询出每个inter…

GaussDB 闪回恢复技术详解与应用实践

一、概述 闪回恢复&#xff08;Flashback Recovery&#xff09;​​ 是 GaussDB 数据库提供的一种高可用性功能&#xff0c;允许用户将数据库快速恢复到过去某一时间点或事务状态&#xff0c;以应对数据误删、逻辑错误或部分数据损坏等问题。相较于传统的全量备份增量恢复方案…

【Mastering Vim 2_07】第六章:正则表达式和 Vim 宏在代码重构中的实战应用

【最新版《Mastering Vim》封面&#xff0c;涵盖 Vim 9.0 版特性】 文章目录 第六章 正则表达式和 Vim 宏在代码重构中的应用1 substitute 替换命令2 关于 substitute 的精确匹配3 参数列表 arglist 在跨文件操作中的应用4 Vim 正则表达式基础5 关于 magic 模式5.1 magic 模式5…

AI创作教程:用deepseek和猫箱做互动故事游戏

年轻的时候我看过典型的玛丽苏文学、小妞文学&#xff0c;老了虽然识破这是给女孩编织的琉璃般的梦&#xff0c;看起来梦幻美丽其实一击就碎&#xff0c;会伤人的碎渣渣。【叠甲完毕】 本来我想用橙光的&#xff0c;但是橙光的话&#xff0c;最好把剧本和立绘都多打磨一下。快…

自动化部署工具Jenkins和Jpom的区别及优缺点,你选择用哪个?

Jenkins和Jpom都是常用的自动化部署工具&#xff0c;但它们在功能、使用场景和架构上有显著差异。以下是它们的优缺点对比&#xff1a; Jenkins 优点&#xff1a; 成熟稳定 &#xff1a;Jenkins是开源CI/CD工具&#xff0c;拥有庞大的社区支持和丰富的插件生态。 高度可扩展 &a…

如何把图片或者图片地址存到 MySQL 数据库中以及如何将这些图片数据通过 JSP 显示在网页中

如何优雅地管理图片&#xff1a;从MySQL数据库存储到JSP展示的全流程解析 在互联网时代&#xff0c;一张引人入胜的图片往往能为网站带来巨大的流量。而作为开发者的我们&#xff0c;如何高效地管理和展示这些图片资源则成为了一项重要的技术挑战。今天&#xff0c;我们就一起…