【算法】最小生成树——普利姆 (Prim) 算法

目录

  • 1.概述
  • 2.代码实现
    • 2.1.邻接矩阵存储图
    • 2.2.邻接表存储图
    • 2.3.测试
  • 3.应用

1.概述

(1)在一给定的无向图 G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边,而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集且为无循环图,使得联通所有结点w(T) 最小,则此 T 为 G 的最小生成树 (minimal spanning tree)

(2)普利姆 (Prim) 算法是一种用于解决最小生成树问题的贪心算法,其主要思路如下:

  • ① 选择任意一个顶点作为起始点,将其加入最小生成树中。
  • ② 从已选择的顶点集合中选取一个顶点,该顶点与未选择的顶点构成的边权重最小,并且该边的另一端顶点未被选择,将该顶点和边加入最小生成树中。
  • ③ 重复步骤 ②,直到最小生成树包含了图中的所有顶点。

(3)例如,对带权连通无向图 G 使用普利姆 (Prim) 算法构造最小生成树的过程如下:

请添加图片描述

另外一种生成最小生成树的克鲁斯卡尔 (Kruskal) 算法可参考【算法】最小生成树——克鲁斯卡尔 (Kruskal) 算法这篇文章。

2.代码实现

2.1.邻接矩阵存储图

class Solution {// INF 表示两点之间没有连接,即无穷大int INF = Integer.MAX_VALUE;/*graph: 用于表示图的邻接矩阵返回值: 路径矩阵*/public int prim(int[][] graph) {//图中的顶点数int V = graph.length;// weight[i] 表示从 i 点到已访问集合的最小边权值int[] weight = new int[V];Arrays.fill(weight, INF);//标记节点是否在最小生成树中boolean[] mstSet = new boolean[V];// parent[i] 表示从 i 点到最小生成树的一条边int[] parent = new int[V];//从顶点 0 开始生成最小树weight[0] = 0;//根节点没有父节点parent[0] = -1;//访问 V - 1 个节点for (int i = 0; i < V - 1; i++) {//从未访问的节点中选择 weight 最小的节点 uint u = minKey(weight, mstSet);//将节点 u 标记为已访问mstSet[u] = true;//访问与 u 相邻的节点 vfor (int v = 0; v < V; v++) {//如果 v 未被访问过、u - v 之间有边、并且 u - v 之间的距离比原本的距离小if (!mstSet[v] && graph[u][v] != 0 && graph[u][v] != INF && graph[u][v] < weight[v]) {//将 u - v 之间的边加入最小生成树parent[v] = u;//标记从 v 到已访问集合的最小边权值weight[v] = graph[u][v];}}}//计算最小生成树的权值并返回int sum = 0;for (int i = 1; i < V; i++) {sum += weight[i];}//输出最小生成树的路径System.out.println("最小生成树的路径以及对应的权重依次为: ");for (int i = 1; i < V; i++) {System.out.println("(" + parent[i] + "-" + i + ") " + weight[i]);}return sum;}public int minKey(int[] weight, boolean[] mstSet) {//初始化 weight 的最小值和对应的节点int min = INF;int minIndex = -1;for (int v = 0; v < weight.length; v++) {//如果 v 节点未被访问,并且 v 节点到已访问集合的边的权值更小if (!mstSet[v] && weight[v] < min) {//更新最小值min = weight[v];//更新 weight 的最小值对应的节点minIndex = v;}}return minIndex;}
}

2.2.邻接表存储图

class Solution {// INF 表示两点之间没有连接,即无穷大int INF = Integer.MAX_VALUE;/*graph: 用于表示图的邻接表返回值: 最小生成树的权重*/public int prim(List<int[]>[] graph) {//图中的顶点数int V = graph.length;// weight[i] 表示从 i 点到已访问集合的最小边权值int[] weight = new int[V];Arrays.fill(weight, INF);//标记节点是否在最小生成树中boolean[] mstSet = new boolean[V];// parent[i] 表示从 i 点到最小生成树的一条边int[] parent = new int[V];//从顶点 0 开始生成最小树weight[0] = 0;//根节点没有父节点parent[0] = -1;//访问 V - 1 个节点for (int i = 0; i < V - 1; i++) {//从未访问的节点中选择 weight 最小的节点 uint u = minKey(weight, mstSet);//将节点 u 标记为已访问mstSet[u] = true;//访问与 u 相邻的节点 vfor (int[] node : graph[u]) {int v = node[0];int w = node[1];if (!mstSet[v] && w < weight[v]) {parent[v] = u;weight[v] = w;}}}//计算最小生成树的权值并返回int sum = 0;for (int i = 1; i < V; i++) {sum += weight[i];}//输出最小生成树的路径System.out.println("最小生成树的路径以及对应的权重依次为: ");for (int i = 1; i < V; i++) {System.out.println("(" + parent[i] + "-" + i + ") " + weight[i]);}return sum;}public int minKey(int[] weight, boolean[] mstSet) {//初始化 weight 的最小值和对应的节点int min = INF;int minIndex = -1;for (int v = 0; v < weight.length; v++) {//如果 v 节点未被访问,并且 v 节点到已访问集合的边的权值更小if (!mstSet[v] && weight[v] < min) {//更新最小值min = weight[v];//更新 weight 的最小值对应的节点minIndex = v;}}return minIndex;}
}

2.3.测试

(1)本测试中的加权无向图如下所示:

在这里插入图片描述

(2)邻接矩阵的测试代码如下:

class Test {public static void main(String[] args) {//图的顶点数int n = 7;int[][] graph = new int[n][n];//初始化邻接矩阵,初始化为 Integer.MAX_VALUE 表示不可达for (int i = 0; i < n; i++) {Arrays.fill(graph[i], Integer.MAX_VALUE);graph[i][i] = 0;}//添加图的边graph[0][1] = 9;graph[0][5] = 1;graph[1][0] = 9;graph[1][2] = 4;graph[1][6] = 3;graph[2][1] = 4;graph[2][3] = 2;graph[3][2] = 2;graph[3][4] = 6;graph[3][6] = 5;graph[4][3] = 6;graph[4][5] = 8;graph[4][6] = 7;graph[5][0] = 1;graph[5][4] = 8;graph[6][1] = 3;graph[6][3] = 5;graph[6][4] = 7;Solution solution = new Solution();int sum = solution.prim(graph);System.out.println("最小生成树的权重为: " + sum);}
}

输出结果如下:

最小生成树的路径以及对应的权重依次为: 
(2-1) 4
(3-2) 2
(4-3) 6
(5-4) 8
(0-5) 1
(1-6) 3
最小生成树的权重为: 24

(3)邻接表的测试代码如下:

class Test {public static void main(String[] args) {//图的顶点数int n = 7;List<int[]>[] graph = new ArrayList[n];//初始化邻接表for (int i = 0; i < n; i++) {graph[i] = new ArrayList<>();}//添加图的边graph[0].add(new int[]{1, 9});graph[0].add(new int[]{5, 1});graph[1].add(new int[]{0, 9});graph[1].add(new int[]{2, 4});graph[1].add(new int[]{6, 3});graph[2].add(new int[]{1, 4});graph[2].add(new int[]{3, 2});graph[3].add(new int[]{2, 2});graph[3].add(new int[]{4, 6});graph[3].add(new int[]{6, 5});graph[4].add(new int[]{3, 6});graph[4].add(new int[]{5, 8});graph[4].add(new int[]{6, 7});graph[5].add(new int[]{0, 1});graph[5].add(new int[]{4, 8});graph[6].add(new int[]{1, 3});graph[6].add(new int[]{3, 5});graph[6].add(new int[]{4, 7});Solution solution = new Solution();int sum = solution.prim(graph);System.out.println("最小生成树的权重为: " + sum);}
}

输出结果如下:

最小生成树的路径以及对应的权重依次为: 
(2-1) 4
(3-2) 2
(4-3) 6
(5-4) 8
(0-5) 1
(1-6) 3
最小生成树的权重为: 24

3.应用

(1)求图的最小生成树许多实际应用,例如城市之间的交通工程造价最优问题就是一个最小生成树问题。

(2)大家可以去 LeetCode 上找相关的最小生成树的题目来练习,或者也可以直接查看 LeetCode 算法刷题目录 (Java) 这篇文章中的最小生成树章节。如果大家发现文章中的错误之处,可在评论区中指出。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenAI 地震!首席执行官被解雇,背后的原因是?

11月17日&#xff0c;ChatGPT的制造商OpenAI表示&#xff0c;经过审查后发现联合创始人兼首席执行官 Sam Altman与董事会“沟通时并不一贯坦诚”&#xff0c;因此公司已经决定解雇他。这家人工智能&#xff08;AI&#xff09;公司在一份声明中表示&#xff1a;“董事会不再相信…

【电路笔记】-欧姆定律

欧姆定律 文章目录 欧姆定律1、概述2、AC电路的等效性2.1 输入电阻2.2 输入电感2.3 输入电容 3、欧姆定律的局部形式3.1 介绍和定义3.2 德鲁德模型(Drude Model)3.3 局部形式表达式 4、电阻和宏观欧姆定律5、总结 电流、电压和电阻之间的基本关系被称为欧姆定律&#xff0c;可能…

黑马天机学堂-2、我的课程表 接口分析与设计

在昨天的学习中&#xff0c;我带领大家解决了天机学堂的简单的BUG。并且演示了整个项目的核心业务流程。现在&#xff0c;你对项目有了基本的了解&#xff0c;是时候动手开发一些业务功能了。 接下来接收到一个正式的开发任务&#xff1a;开发天机学堂项目的学习辅助相关功能。…

最新版微信如何打开青少年模式?

最新版微信如何打开青少年模式&#xff1f; 1、将手机微信升级到最新版&#xff0c;并打开后点击底部我的进入&#xff1b; 2、在我的内&#xff0c;找到并点击设置进入&#xff1b; 3、在设置内找到青少年模式&#xff0c;并点击进入开启微信青少年模式&#xff1b; 原文来源…

解决SLF4J: Class path contains multiple SLF4J bindings.

这个问题在使用Dubbo时产生&#xff0c;推荐一个插件Maven Helper 1.插件安装 安装好后下方会有一个Dependency Analyzer&#xff0c;点击进入 2.删除冲突项 根据报错信息选择一个slf4j删除&#xff0c;不一定是slf4j-log4j12&#xff0c;每个人的报错信息不一样&#xff0c;图…

单图像3D重建AI算法综述【2023】

计算机视觉是人工智能的一个快速发展的领域&#xff0c;特别是在 3D 领域。 本概述将考虑一个应用任务&#xff1a;2D 和 3D 环境之间的转换。 在线工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编…

贝锐蒲公英云AP,企业WiFi功能如何使用?

1. 功能介绍 基于WPA2-EAP安全认证技术&#xff0c;为企业提供了一套易用安全的企业无线网络,实现企业员工通过蒲公英客户端一键连接企业无线WiFi。自动分配一人一帐一密&#xff0c;无需配置证书或手动输入密码&#xff0c;减少沟通成本&#xff0c;方便快捷&#xff0c;提高…

Docker中的RabbitMQ已经启动运行,但是管理界面打不开

文章目录 前言一、解决方法方法一方法二 总结 前言 肯定有好多小伙伴在学习RabbitMQ的过程中&#xff0c;发现镜像运行&#xff0c;但是我的管理界面怎么进不去&#xff0c;或者说我第一天可以进去&#xff0c;怎么第二天进不去了&#xff0c;为什么每次重新打开虚拟机都进不去…

C/C++高精度

个人主页&#xff1a;仍有未知等待探索_C语言疑难,数据结构,小项目-CSDN博客 专题分栏&#xff1a;算法_仍有未知等待探索的博客-CSDN博客 为什么需要高精度算法&#xff1f; 由于c不能进行位数过高的数据运算&#xff0c;所以要通过模拟数组来进行运算&#xff0c;首先是加法。…

.babyk勒索病毒解析:恶意更新如何威胁您的数据安全

导言&#xff1a; 在数字时代&#xff0c;威胁不断进化&#xff0c;其中之一就是.babyk勒索病毒。这种病毒采用高级加密算法&#xff0c;将用户文件锁定&#xff0c;并要求支付赎金以获取解密密钥。本文91数据恢复将深入介绍.babyk勒索病毒的特点、如何应对被加密的数据&#…

(1)(1.17) Maxbotix 模拟声纳

文章目录 前言 1 连接到Pixhawk 2 通过Mission Planner进行设置 3 测试传感器 4 参数说明 前言 XL-Maxbotix-EZ 系列模拟声纳&#xff08;XL-MaxSonar-EZ0、EZ4 和 EZL0&#xff09;是相对便宜的短距离&#xff08;7m 至 10m&#xff09;测距仪&#xff0c;主要设计用于室…

实施方法论

软件实施方法论(通用) 软件项目实施交付模型很多领域流传着别人家的传说&#xff1a;别人家的孩子学习成绩好才艺多还长得帅&#xff0c;别人家的客户钱多人傻速来&#xff0c;别人家的公司不加班产品做得好工资还发的倍儿高。这一切事情实际上都有常量和变量&#xff0c;比如…