【算法】最小生成树——普利姆 (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.mzph.cn/news/155586.shtml

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

相关文章

湖科大计网:应用层

一、应用层概述 交互&#xff0c;实现特定问题&#xff01; 二、客户与服务器模型 一、C/S 客户/服务器方式 服务与被服务的关系。 二、P2P方式 对等方式 P2P方式是对等的&#xff0c;没有固定的服务器。 三、DNS域名系统 DNS&#xff08;Domain Name System&#xff09; 一、域…

2018年计网408

第33题 下列 TCP/P应用层协议中, 可以使用传输层无连接服务的是()A. FTPB. DNSC. SMTPD. HTTP 本题考察TCP/IP体系结构中&#xff0c;应用层常用协议所使用的运输层服务。 如图所示。这是TCP/IP体系结构中常见应用层协议各自所使用的运输层端口,。在这些应用层协议中&#x…

uvm白皮书练习_ch2_ch231_加入transaction

2.3 为验证平平台加入各种组件 uvm白皮书练习_ch2_ch231_加入transaction 代码部分 top_tb.sv timescale 1ns / 1ps include "uvm_macros.svh"import uvm_pkg::*; /*只能现在*/include "my_if.sv" include "my_transaction.sv" include "…

Vue Router的使用

Vue.js是一个流行的JavaScript框架&#xff0c;用于开发单页面应用程序。Vue提供了一个强大的路由系统&#xff0c;可以帮助我们管理应用程序中的不同页面。在本文中&#xff0c;我们将详细讲解Vue路由的使用方法。 目录 1. 安装Vue Router2. 创建路由实例3. 配置路由4. 在模板…

关闭bitlocker加密

windows11的笔记本电脑买回来发现分驱都处于bitlocker状态&#xff0c;上网上搜索都是说进入控制面板的安全项进行关闭&#xff0c;包括去搜索栏搜索“管理 BitLocker”&#xff0c;对搜索出来的项打开&#xff0c;经过试验&#xff0c;它们进入的是同一个位置&#xff0c;只有…

互动直播 之 视频帧原始数据管理

目录 一、视频帧管理 1、存储图片数据的数据结构 1.1)、图片数据首地址

【docker】虚拟化和docker容器概念

基础了解 IAAS&#xff1a; 基础设施服务&#xff0c;&#xff08;只提供基础设施&#xff0c;没有系统&#xff09; **SAAS&#xff1a; ** 软件即服务&#xff0c;&#xff08;提供基础设施和系统&#xff09; PAAS&#xff1a; 平台即服务&#xff0c;&#xff08;提供基…

SwiftUI 如何动态开始和停止播放永久重复(repeatForever)动画

0. 功能需求 在 SwiftUI 丰富多彩的动画世界中,我们有时希望可以随意开始和停止永久循环(repeatForever)的动画,不过这时往往会产生错误的动画“叠加”效果。 从上图可以看到:虽然我们希望密码输入框背景只在用户输入密码时才发生闪烁,但顶部的密码输入框随着不断输入其…

Yii2 ActiveRecord连接OpenGauss提示表不存在table not exist

1.修改数据库连接信息 文件位置 config/db.php 添加默认Schema return [class > yii\db\Connection,dsn > pgsql:host127.0.0.1;port5432;dbnamepostgres,username > postgres,password > Pass123,charset > utf8,//enableSchemaCache > true,//表结构是否…

Linux02 VIM编辑器

Linux02 VIM编辑器 基本上 vi/vim 共分为三种模式&#xff0c; 分别是命令模式&#xff08;Command mode&#xff09;&#xff0c;输入模式&#xff08;Insert mode&#xff09;和底线命令模式&#xff08;Last line mode&#xff09;。 三种状态进行切换 插入模式&#xff1a…

Java入门篇 之 内部类

本篇碎碎念&#xff1a;本篇没有碎碎念&#xff0c;想分享一段话&#xff1a; 你不笨&#xff0c;你只是需要时间&#xff0c;耐心就是智慧&#xff0c;不见得快就好&#xff0c;如果方向都不对&#xff0c;如果心术不正&#xff0c;如果德不配位&#xff0c;快就是对自己天分的…

【数值计算方法】矩阵特征值与特征向量的计算(一):Jacobi 旋转法及其Python实现

文章目录 一、Jacobi 旋转法1. 基本思想2. 计算过程演示3. 注意事项 二、Python实现迭代过程&#xff08;调试&#xff09; 矩阵的特征值&#xff08;eigenvalue&#xff09;和特征向量&#xff08;eigenvector&#xff09;在很多应用中都具有重要的数学和物理意义。Jacobi 旋转…

软件工程理论与实践 (吕云翔) 第十二章 软件测试概述课后习题及其答案解析

第十二章 软件测试概述 1.判断题 &#xff08;1&#xff09;软件测试是对软件规格说明、软件设计和编码的最全面也是最后的审查。&#xff08;) 解析&#xff1a;软件测试是一个独立的活动&#xff0c;旨在评估软件的质量和发现潜在的问题&#xff0c;而不仅仅是对规格说明、…

六、流量监管、流量整形

流量监管、流量整形 流量监管、流量整形1.1.定义1.2.简单流分类应用场景举例1.3.简单流分类的配置1.4.复杂流分类1.5.复杂流分类在产品中的实现 ————————————————— 流量监管、流量整形 当报文的发送速率大于接收速率&#xff0c;或者下游设备的接口速率小于…

使用Python合并pdf文件

import PyPDF2 # 创建一个空的 PDF 文档对象 def pdf_merge(path_a,path_b,path_save):merged_pdf PyPDF2.PdfMerger()# 打开第一个 PDF 文件&#xff0c;读取其内容并追加到新创建的 PDF 文档对象中with open(path_a, rb) as file1:merged_pdf.append(file1)# 打开第二个 PDF…

GitHub 2023报告-开源和AI的现状

GitHub 2023报告-开源和AI的现状 深入探讨人工智能如何与开源互动&#xff0c;以及未来几年可能出现的趋势。 背景介绍 2023年&#xff0c;开源已成为全球软件开发的标准。无论是大公司还是小团队&#xff0c;都广泛使用开源技术进行项目开发。此外&#xff0c;随着机器学习和…

Docker部署FLASK Unicorn并配置Nginx

1. 安装相关依赖 flask3.0.0 pymysql1.1.0 #我自己需要的 flask_cors4.0.0 gunicorn21.2.0 gevent23.9.12. 配置Gunicorn 新建gunicorn.conf.py bind 0.0.0.0:5418 # 绑定的IP地址和端口 workers 8 # 同时执行的进程数&#xff0c;推荐为当前CPU个数*21 worker_class&qu…

【Java】java | CacheManager | redisCacheManager

一、说明 1、查询增加缓存&#xff0c;使用Cacheable注解 2、项目中已经用到了ehcache&#xff0c;现在需求是两个都用 二、备份配置 1、redisConfig增加代码 Bean("redisCacheManage")Primarypublic CacheManager redisCacheManager(RedisConnectionFactory fact…

项目集成的关键过程总结

项目集成是确保项目各部分协调一致&#xff0c;共同实现项目目标的过程。以下是项目集成的关键过程&#xff1a; 制定集成计划 制定集成计划是项目集成的第一步。该计划应明确集成的目标、范围、时间表、资源分配和风险管理策略。在制定集成计划时&#xff0c;需要考虑项目干…

CKD TransBTS:用于脑肿瘤分割的具有模态相关交叉注意的临床知识驱动混合转换器

CKD-TransBTS: Clinical Knowledge-Driven Hybrid Transformer With Modality-Correlated Cross-Attention for Brain Tumor Segmentation CKD TransBTS&#xff1a;用于脑肿瘤分割的具有模态相关交叉注意的临床知识驱动混合转换器背景贡献实验方法how radiologists diagnose b…