【图】最小生成数—Kruskal算法

目录

1. 什么是最小生成树?

2. Kruskal算法


1. 什么是最小生成树?

最小生成树(Minimum Spanning Tree,简称 MST)是指在一个连通无向图中,找到一个包含所有顶点的树,并且边的权值之和最小。

连通图:是指图中任意两个顶点之间都存在路径的图。

连通图中的每一棵生成树,都是原图的一个极大无环子图,即:从其中删去任何一条边,生成树 就不再连通;反之,在其中引入任何一条新边,都会形成一条回路
若连通图由n个顶点组成,则其生成树必含n个顶点和n-1条边。因此构造最小生成树的准则有三 条:
  1. 只能使用图中的边来构造最小生成树
  2. 只能使用恰好n-1条边来连接图中的n个顶点
  3. 选用的n-1条边不能构成回路
构造最小生成树的方法:Kruskal算法Prim算法。这两个算法都采用了逐步求解的贪心策略

2. Kruskal算法

算法描述:

  • 任给n个顶点;
  • 首先构造一个由这n个顶点组成、不含任何边的图,其中每个顶点自成一个连通分量;
  • 以顶点的每条边的权值排序(小->大),依次遍历排序后的边,对于每条边 (u, v),如果将其加入最小生成树不会形成回路,则将其加入图/最小生成树,并将顶点 u 和 v 合并为一个连通分量;
  • 如此重复,直到该图/最小生成树包含了图中的所有顶点。

直接拿例题中的示例模拟一下过程:

1584. 连接所有点的最小费用

给你一个points 数组,表示 2D 平面上的一些点,其中 points[i] = [xi, yi] 。

连接点 [xi, yi] 和点 [xj, yj] 的费用为它们之间的 曼哈顿距离 :|xi - xj| + |yi - yj| ,其中 |val| 表示 val 的绝对值。

请你返回将所有点连接的最小总费用。只有任意两点之间 有且仅有 一条简单路径时,才认为所有点都已连接。

根据算法原理进行分析:

  • 该图有5个顶点,任意一个顶点会有4条边,对于无向图来说A-B和B-A是同一条边。
  • 每个顶点是一个连通分量,我们先不管它。
  • 要对所有边进行排序,不断选取权值最小的一条,对于这一步,我们需要将所有边保存起来,并且不能重复存边(如A-B,B-A只能存一次)。
  • 每次选取的边,如果加入后,图中不会形成环(即这条边的两个顶点不能已经是一个连通块),则加入该条边,并将两个顶点合并成一个连通块。否则往后选取。

  •  反复上述操作,直到找到n-1条边,就找到了最小生成树。

本题的代码实现:

  1. 边与顶点的关系,用一个类edge进行描述。
  2. 边的排序,可以用ArrayList,我这里用的是优先级队列。
  3. 维护每个顶点之间的连通关系,这里最好就是使用并查集。【并查集】一种简单而强大高效的数据结构
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;

public class LeetCode1584 {
    //1584. 连接所有点的最小费用
    static class Edge {
        private int len; //权值
        private int x; //顶点
        private int y; //顶点

        public Edge(int len, int x, int y) {
            this.len = len;
            this.x = x;
            this.y = y;
        }
    }

    public int minCostConnectPoints(int[][] points) {
        int n = points.length;
        //1.将连通图的所有边加入到优先级队列(以权值建小根堆)
        PriorityQueue<Edge> pq = new PriorityQueue<>(Comparator.comparingInt(o -> o.len));
        for (int i = 0; i < n; i++) {
            //不要重复存边
            for (int j = i + 1; j < n; j++) {
                int x = Math.abs(points[j][0] - points[i][0]);
                int y = Math.abs(points[j][1] - points[i][1]);
                pq.offer(new Edge((x + y), i, j));
            }
        }
        //2.贪心策略选边,并把选到边的对应两个顶点合并成一个连通块
        int count = 0;
        UnionFindSet ufs = new UnionFindSet(n);
        int sum = 0;
        while (!pq.isEmpty()) {
            Edge edge = pq.poll();
            int len = edge.len, x = edge.x, y = edge.y;
            //如果两个顶点不构成连通块,将结果加上这条边,并合并两个顶点
            if (ufs.union(x, y)) {
                sum += len;
                //n个顶点,选n - 1条边
                if (++count == n - 1) {
                    break;
                }
            }
        }
        return sum;
    }

    public static void main(String[] args) {
        System.out.println(new LeetCode1584().minCostConnectPoints(new int[][]{
                {0, 0}, {2, 2}, {3, 10}, {5, 2}, {7, 0}
        }));
    }
}

class UnionFindSet {

    //elem的值表示:如果大于0,表示这个点的父节点下标;如果小于0,表示该点是一个集合
    private int[] elem;

    public UnionFindSet(int n) { //参数n表示顶点个数
        this.elem = new int[n];
        Arrays.fill(elem, -1);
    }

    //合并两个顶点
    public boolean union(int x, int y) {
        x = find(x);
        y = find(y);
        //两个顶点已经是在同一个集合里了
        if (x == y) return false;
        elem[x] += elem[y];
        elem[y] = x;
        return true;
    }

    private int find(int x) {
        while (elem[x] >= 0) {
            x = elem[x];
        }
        return x;
    }
}

首先创建了一个小根堆优先队列,用来存储所有的边,并按照边的权值从小到大排序。然后通过贪心策略选取边,确保选择的边不会形成环路,并且合并相应的顶点,直到选取了足够数量的边,形成了最小生成树。

同时,还实现了一个并查集(UnionFindSet)来维护顶点之间的连通性,这是 Kruskal 算法的关键之一。这里的并查集并不用实现很多功能,根据题目需求自行调整代码逻辑,这样的效率更高。比如在合并的时候,就判断两个顶点是否已在同一个连通块,针对其返回值确定是否要加入最小生成树。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/514237.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

简单的安全密码生成器PwGen

什么是 PwGen &#xff1f; PwGen 是一个简单的 Docker Web 应用程序&#xff0c;旨在生成具有可自定义选项的安全密码或密码短语。用户可以选择生成具有特定标准的随机密码或由随机单词组成的密码。其他功能包括在密码中包含大写字母、数字和特殊字符的选项&#xff0c;或者将…

边缘计算盒子与云计算:谁更适合您的业务需求?

边缘计算盒子和云计算&#xff0c;这两个概念听起来可能有点复杂&#xff0c;但其实它们就是两种不同的数据处理方式。那谁更适合您的业务需求呢&#xff1f;咱们来详细说说。 边缘计算盒子&#xff0c;就像是个小型的数据处理中心&#xff0c;放在离你业务现场比较近的地方。它…

解决Flutter应用在苹果商店上架中常见的问题与挑战

引言 Flutter是一款由Google推出的跨平台移动应用开发框架&#xff0c;其强大的性能和流畅的用户体验使其备受开发者青睐。然而&#xff0c;开发一款应用只是第一步&#xff0c;将其成功上架到苹果商店才是实现商业目标的关键一步。本文将详细介绍如何使用Flutter将应用程序上…

【Unity每日一记】(Canvas的相机渲染模式) 如何将模型显示在UI之前

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

CSS——精灵图

CSS——精灵图 目录 CSS——精灵图什么是精灵图&#xff1f;导入精灵图裁剪精灵图使用精灵图方式1方式2 什么是精灵图&#xff1f; 精灵图&#xff08;Spritesheet&#xff09;是指将多个小图标、图像或动画合并到一个大图像中的技术。在网页设计和游戏开发中&#xff0c;精灵…

AlgorithmStar(AS机器学习与科学计算库) 实现 矩阵数据类型的计算函数汇总

AlgorithmStar 实现 矩阵 计算 AlgorithmStar 本文中将会演示通过 AS 机器学习库 实现 矩阵计算 目录 文章目录 AlgorithmStar 实现 矩阵 计算目录矩阵创建通过数组创建通过稀疏矩阵创建通过填充创建矩阵通过随机的方式创建矩阵 矩阵计算矩阵的基本运算矩阵的加法计算矩阵的减…

【Erlang】Linux(CentOS7)安装Erlang和RabbitMQ

一、系统环境 查版本对应&#xff0c;CentOS-7&#xff0c;选择Erlang 23.3.4&#xff0c;RabbitMQ 3.9.16 二、操作步骤 安装 Erlang repository curl -s https://packagecloud.io/install/repositories/rabbitmq/erlang/script.rpm.sh | sudo bash安装 Erlang package s…

【TI毫米波雷达】官方工业雷达包的生命体征检测环境配置及避坑(Vital_Signs、IWR6843AOPEVM)

【TI毫米波雷达】官方工业雷达包的生命体征检测环境配置及避坑&#xff08;Vital_Signs、IWR6843AOPEVM&#xff09; 文章目录 生命体征基本介绍IWR6843AOPEVM的配置上位机配置文件避坑上位机start测试距离检测心跳检测呼吸频率检测空环境测试 附录&#xff1a;结构框架雷达基…

【Python系列】Python中的YAML数据读取与解析

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

物联网实战--入门篇之(十二)完结

目录 一、涉及的知识点 二、物联网现状 三、物联网前景 四、文章方向 这篇文章主要对这个项目做个总结&#xff0c;以及对于物联网今后的学习方向。 一、涉及的知识点 不得不说&#xff0c;物联涉及确实很广&#xff0c;就净化器这个小项目来说&#xff0c; 编程语言&…

【Jenkins】关于账号,证书验证的设置问题

当你的电脑启动了Jenkins&#xff0c;这时候一定要小心更改管理员账号和密码~~~ 当你的电脑启动了Jenkins&#xff0c;这时候一定要小心更改管理员账号和密码~~~ 当你的电脑启动了Jenkins&#xff0c;这时候一定要小心更改管理员账号和密码~~~ 重要的事情说3遍&#xff0c;如…

【Java核心能力】饿了么一面:Redis 面试连环炮

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…

ES6学习(四)-- Reflect / Promise / Generator 函数 / Class

文章目录 1. Reflect1.1 代替Object 的某些方法1.2 修改某些Object 方法返回结果1.3 命令式变为函数行为1.4 ! 配合Proxy 2. ! Promise2.1 回调地狱2.2 Promise 使用2.3 Promise 对象的状态2.4 解决回调地狱的方法2.5 Promise.all2.6 Promise.race 3. Generator 函数3.1 基本语…

MySQL执行流程

MySQL执行流程 在使用MySQL时&#xff0c;你是否有疑惑&#xff0c;当我们提交一条SQL给MySQL时它到底是如何执行的&#xff1f; 通过了解MySQL的执行流程一定能解开你的疑惑&#x1f914; 总体流程 客户端通过连接器连接MySQL查询执行缓存解析器解析SQL执行器执行SQL调用存…

非小米电脑下载小米电脑管家

由于 小米电脑管家 现在新增了机型验证&#xff0c;本篇将分享非小米电脑用户如何绕过机型验证安装 小米电脑管家 首先到小米跨端智联官网 https://hyperos.mi.com/continuity 中下载小米电脑管家 打开官网链接后&#xff0c;直接滑动到底部&#xff0c;点击下载 下载完成后…

鸿蒙OS开发实例:【组件化模式】

组件化一直是移动端比较流行的开发方式&#xff0c;有着编译运行快&#xff0c;业务逻辑分明&#xff0c;任务划分清晰等优点&#xff0c;针对Android端的组件化&#xff1b;与Android端的组件化相比&#xff0c;HarmonyOS的组件化可以说实现起来就颇费一番周折&#xff0c;因为…

数据转换 | Matlab基于GASF格拉姆角和场一维数据转二维图像方法

目录 效果分析基本介绍程序设计参考资料获取方式 效果分析 基本介绍 基于GASF&#xff08;Gramian Angular Summation Field&#xff09;的方法&#xff0c;将一维数据转换为二维图像的步骤描述 标准化数据&#xff1a; 首先&#xff0c;对一维时序数据进行标准化处理&#xf…

canal部署

定义 canal组件是一个基于mysql数据库增量日志解析&#xff0c;提供增量数据订阅和消费&#xff0c;支持将增量数据投递到下游消费者&#xff08;kafka&#xff0c;rocketmq等&#xff09;或者存储&#xff08;elasticearch,hbase等&#xff09;canal感知到mysql数据变动&…

.Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置

.Net Core/.Net6/.Net8 &#xff0c;启动配置/Program.cs 配置 没有废话&#xff0c;直接上代码调用 没有废话&#xff0c;直接上代码 /// <summary>/// 启动类/// </summary>public static class Mains{static IServiceCollection _services;static IMvcBuilder _…

2012年认证杯SPSSPRO杯数学建模D题(第一阶段)人机游戏中的数学模型全过程文档及程序

2012年认证杯SPSSPRO杯数学建模 减缓热岛效应 D题 人机游戏中的数学模型 原题再现&#xff1a; 计算机游戏在社会和生活中享有特殊地位。游戏设计者主要考虑易学性、趣味性和界面友好性。趣味性是本质吸引力&#xff0c;使玩游戏者百玩不厌。网络游戏一般考虑如何搭建安全可…