图搜索算法-最小生成树问题-克鲁斯卡尔算法(kruskal)

相关文章:
数据结构–图的概念
图搜索算法 - 深度优先搜索法(DFS)
图搜索算法 - 广度优先搜索法(BFS)
图搜索算法 - 拓扑排序
图搜索算法-最短路径算法-戴克斯特拉算法
图搜索算法-最短路径算法-贝尔曼-福特算法

最小生成树

首先认识什么叫生成树(spanning tree),一个有N个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有N个结点,并且有保持图连通的最少的边,如图所示。
在这里插入图片描述

最小生成树(Minimum Spanning Tree)问题(下面简称MST)是指给定连接图G具有正的边权重,找到连接所有结点的边的最小权重集。MST应用场景多为网络设计,如光纤网络、燃气管道网络、电缆、道路交通等路线设计,其问题可以用克鲁斯卡尔(kruskal)算法或普里姆(prim)算法求解。

克鲁斯卡尔算法(kruskal)

这里有一个案例,一家公司在6个城市有分公司,他们之间需要用专用电话线路链接起来,电信公司给出了每个城市之间铺设线路的费用,如图所示。现在需要设计一个方案,用最少费用完成这个电话线路铺设。
在这里插入图片描述
面对这个问题,自然会想到尽量选择最小权重的边,结果必然是最小了。在算法里面,称为贪心算法。基本思想是通过获得局部的最优解,从而得到最终的最优解。现在要使用的克鲁斯卡尔算法核心思想是贪心算法,目标非常明确简单,步骤如下。
(1)初始化一个生成树集合(简称MST)为空。
(2)按边的权重由大到小进行排序。
(3)选择最小权重的边,检查它是否与MST形成一个循环图。如果没有形成循环图,则把该边放进MST,否则将其丢弃。
(4)重复步骤3,直到生成树中有(N-1)个边(N为结点数)。
分析步骤,克鲁斯卡尔算法最多遍历E条边,每次选择最小代价的边仅需要O(logE)的时间,因此,克鲁斯卡尔算法的时间复杂度为O(ElogE),空间上需要一个N-1空间记录最小生成树,所以空间复杂度为O(N)。现在尝试手动计算求解,首先是边权重的排序,结果如表所示。
在这里插入图片描述
然后选择权重最小的边【上海-武汉】,因此MST初始值为空,当然没有循环图,所以不存在循环图,当然把这条边放进MST中,接着挑选边【广州-成都】,同样也不存在循环图,如图所示。
在这里插入图片描述
用同样的方式,选择【广州-厦门】、【广州-武汉】都进入了MST,然后挑选【厦门-武汉】,这时候就形成了一个循环,因此丢弃此边,当前MST的状态如下图所示。
在这里插入图片描述
紧接着选择【厦门-上海】,同样也形成了循环,同样不能放到MST中。然后继续选择【北京-上海】,这条边则成功进入MST中,此时MST的边数量已经达到5个,满足结束条件,最终结果如下图6-8所示。此图也就是电话路线的铺设方案,总费用是MST上所有边的权重和为14。
在这里插入图片描述
用代码来表现此算法,首先知道这是一个有权无向图,则使用邻居列表并且带有权重,【Graph】类的输入不适用于这里,需要创建新的类叫【GraphPower】。

class GraphPower(): """有权图类"""def __init__(self, points):self.amount = len(points) # 记录结点的总数self.points = points      # 记录结点位置和值的关系self.graph = []           #  初始化图的邻接列表def add_edge(self, u, v, w):if u in self.points and v in self.points:index_u = self.points.index(u)index_v = self.points.index(v)self.graph.append([index_u, index_v, w]) # 录入数据else:print("录入数据有误")

算法的过程在此,创建【GraphKruskal】类,kruskalMST()函数是克鲁斯卡尔算法主体,然后用不相交集来检验是否有循环出现。

class GraphKruskal(GraphPower): """克鲁斯卡尔算法,输入的是有权无向图,求解最小生成树"""def find(self, parent, i):# 寻找其父结点if parent[i] == i: return i return self.find(parent, parent[i])def kruskalMST(self):# 基于不相交集实现克鲁斯卡尔算法主程序# 第一步初始化MST =[] # 初始化MST,也是最终结果 parent = [] # 初始化列表记录结点的相交连接结点下标,用于检测是否有循环for node in range(self.amount): # 每一个结点创建一个子集合 parent.append(node) index_sorted_edge = 0 # 根据权重已排序的边的下标 index_reslut = 0 # MST列表中的下标 # 第二步,根据权重排序self.graph = sorted(self.graph,key=lambda item: item[2]) # 权重w在item中的三个位置while len(MST) < self.amount -1 : # 结束条件:直到生成树中有(N-1)个边 # 第三步,选择最小权重的边u,v,w = self.graph[index_sorted_edge] index_sorted_edge = index_sorted_edge + 1# 检查它是否与MST形成一个循环图。如果没有形成循环图,则把该边放进MST,否则将其丢弃parent1 = self.find(parent, u) parent2 = self.find(parent ,v)if parent1 != parent2:MST.append([u,v,w])         # 结果中添加新的边parent[parent2] = parent1  # 更新不相交集self.print_result(MST)def print_result(self, result):print("输出最小生成树结果")total = 0for u,v,weight in result:total += weightprint ("{} -- {} == {}".format(self.points[u], self.points[v],weight))else:print("权重总和为:%d" % total)

用例子作为输入来验证结果,运行情况如下。

g = GraphKruskal(["广州","厦门","成都","武汉","上海","北京"]) 
g.add_edge("广州","厦门", 2)
g.add_edge("广州","武汉", 3) 
g.add_edge("广州","成都", 2) 
g.add_edge("武汉","厦门", 4) 
g.add_edge("武汉","成都", 8) 
g.add_edge("武汉","上海", 1) 
g.add_edge("武汉","北京", 9)
g.add_edge("厦门","上海", 5)
g.add_edge("成都","北京", 7)
g.add_edge("上海","北京", 6)
g.kruskalMST()
# ------------结果------------------
输出最小生成树结果
武汉 -- 上海 == 1
广州 -- 厦门 == 2
广州 -- 成都 == 2
广州 -- 武汉 == 3
上海 -- 北京 == 6
权重总和为:14

更多内容

想获取完整代码或更多相关图的算法内容,请查看我的书籍:《数据结构和算法基础Python语言实现》

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

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

相关文章

初识C++ · string的使用(2)

目录 1 Modifiers部分 1.1 assign的使用 1.2 insert的使用 1.3 erase的使用 1.4 replace的使用 2 capacity部分 2.1 max_size的使用 2.2 capacity的使用 2.3 reserve的使用 2.4 shrink_to_fit简介 2.5 resize的使用 2.6 clear的使用 3 String operations部分 3.1 …

【js刷题:数据结构链表之设计链表】

设计链表 一、题目二、题解 一、题目 二、题解 // 定义节点类&#xff0c;每个节点都有一个值和一个指向下一个节点的引用 class LinkNode{constructor(val,next){ // 构造函数&#xff0c;接收节点值和下一个节点的引用this.valval // 节点的值this.nextnext // 指…

视频号视频怎么下载?推荐视频号下载助手机器人工具

本文今天要讲视频号视频怎么下载相关内容&#xff0c;文章中使用了视频号下载助手机器人&#xff0c;建议了解一下。 什么是视频号下载助手机器人? 视频号本身不具备视频下载功能&#xff0c;在微信平台随者软件不断的更新迭代微信视频号早已不在有复制视频号链接功能。 故…

1060 爱丁顿数(测试点5)

solution1&#xff08;测试点5不通过&#xff09; 所谓“E天骑行超过E公里”&#xff0c;注意没有要求是第E天 对于直接判断变成了第E天骑行距离超过E公里&#xff0c;曲解了题意 例如对于 3 1 2 3输出为1 第1天骑行3公里&#xff0c;满足条件&#xff1b;第2天骑行2公里&…

【CTF MISC】XCTF GFSJ0513 pdf Writeup(PDF隐写)

pdf 菜猫给了菜狗一张图&#xff0c;说图下面什么都没有 解法 打开 pdf&#xff0c;只看见一张图片。 用浏览器搜索 flag&#xff0c;发现图片中间藏了一行字。 复制出来&#xff0c;得到 flag。 Flag flag{security_through_obscurity}声明 本博客上发布的所有关于网络攻…

用HAL库改写江科大的stm32入门例子4-1 OLED

大体 步骤&#xff1a; step1&#xff1a;使用STM32CubeMX初始化I2C1&#xff0c;生成初始化代码 step2&#xff1a;将任意一个库导入到工程&#xff0c;配置好编译路径 step3&#xff1a;调用函数即可 IIC原理图&#xff1a; 接线图&#xff1a; 先设置clock&#xff1a; 开…

MHD、MQA、GQA注意力机制详解

MHD、MQA、GQA注意力机制详解 注意力机制详解及代码前言&#xff1a;MHAMQAGQA 注意力机制详解及代码 前言&#xff1a; 自回归解码器推理是 Transformer 模型的 一个严重瓶颈&#xff0c;因为在每个解码步骤中加 载解码器权重以及所有注意键和值会产生 内存带宽开销 下图为三…

如何快速找出文件夹里的全部带有中文纯中文的文件

首先&#xff0c;需要用到的这个工具&#xff1a; 度娘网盘 提取码&#xff1a;qwu2 蓝奏云 提取码&#xff1a;2r1z 步骤 1、打开工具&#xff0c;切换到批量复制文件 2、鼠标移到右侧&#xff0c;点击搜索添加 3、设定查找范围、指定为文件、勾选 包含全部子文件夹&#x…

vue 点击平滑到指定位置并绑定页面滑动效果

1.html元素 写出对应的数据块&#xff08;注意添加ref) 用于获取元素位置 <template><div class"index-page" ><div class"top-head" ref"index"><img src"logo.png" style"height: 40px;margin-right: 2…

一图流解释Java中线程状态的转换

目录 一.Java中的几大线程状态 二.线程之间的相互转换 ▐ NEW --> RUNNABLE ▐ RUNNABLE <--> WAITING ▐ RUNNABLE <--> Timed Waiting ▐ RUNNABLE<--> BLOCKED ▐ RUNNABLE<-->TERMINATED 一.Java中的几大线程状态 简单来说线程可以处于…

Unity里的Time

Time and frame rate management Time类&#xff1a; Time script reference page. 一些常见的属性有&#xff1a; Time.time 返回从游戏开始经历的时间.Time.deltaTime 返回从上帧结束到现在经历的时间&#xff0c;和帧率成反比Time.timeScale 控制时间流逝的因子Time.fixe…

STM32_HAL_TIM_通用计时器_实现计时

项目思路 1使用定时器计数每秒一次 2使用一个变量记录定时器响应多少次 3使用UART将记录的次数发出 1STM32Cude设置 1配置时钟源 2打开UART 3打开TIM2 3.1界面介绍 3.2选项介绍 Slave Mode&#xff08;从模式&#xff09;&#xff1a;当设备被设置为从模式时&#xff0c…