【贪心】最小生成树Kruskal算法Python实现

文章目录

    • @[toc]
      • 问题描述
      • 最小生成树的性质
        • 证明
      • `Kruskal`算法
      • 时间复杂性
      • `Python`实现

因上努力

个人主页:丷从心

系列专栏:贪心算法

果上随缘


问题描述

  • G = ( V , E ) G = (V , E) G=(V,E)是无向连通带权图, E E E中每条边 ( v , w ) (v , w) (v,w)的权为 c [ v ] [ w ] c[v][w] c[v][w]
  • 如果 G G G的一个子图 G ′ G^{'} G是一棵包含 G G G的所有顶点的树,则称 G ′ G^{'} G G G G的生成树
  • 生成树上各边权的总和称为该生成树的耗费,在 G G G的所有生成树中,耗费最小的生成树称为 G G G的最小生成树

最小生成树的性质

  • G = ( V , E ) G = (V , E) G=(V,E)是连通带权图, U U U V V V的真子集,如果 ( u , v ) ∈ E (u , v) \in E (u,v)E,且 u ∈ U u \in U uU v ∈ V − U v \in V - U vVU,且在所有这样的边中, ( u , v ) (u , v) (u,v)的权 c [ u ] [ v ] c[u][v] c[u][v]最小,那么一定存在 G G G的一棵最小生成树,它以 ( u , v ) (u , v) (u,v)为其中一条边
  • 这个性质有时也称为 M S T MST MST性质
证明
  • 假设 G G G的任何一棵最小生成树都不包含边 ( u , v ) (u , v) (u,v),将边 ( u , v ) (u , v) (u,v)添加到 G G G的一棵最小生成树 T T T上,将产生含有边 ( u , v ) (u , v) (u,v)的圈,并且在这个圈上有一条不同于 ( u , v ) (u , v) (u,v)的边 ( u ′ , v ′ ) (u^{'} , v^{'}) (u,v),使得 u ′ ∈ U u^{'} \in U uU v ′ ∈ V − U v^{'} \in V - U vVU,如下图所示

1

  • 将边 ( u ′ , v ′ ) (u^{'} , v^{'}) (u,v)删去,得到 G G G的另一棵生成树 T ′ T^{'} T,由于 c [ u ] [ v ] ≤ c [ u ′ ] [ v ′ ] c[u][v] \leq c[u^{'}][v^{'}] c[u][v]c[u][v],所以 T ′ T^{'} T的耗费 ≤ T \leq T T的耗费,于是 T ′ T^{'} T是一棵含有边 ( u , v ) (u , v) (u,v)的最小生成树,与假设矛盾

Kruskal算法

  • 给定无向连通带权图 G = ( V , E ) G = (V , E) G=(V,E) V = {   1 , 2 , ⋯   , n   } V = \set{1 , 2 , \cdots , n} V={1,2,,n}
  • 首先将 G G G n n n个顶点看成 n n n个孤立的连通分支,将所有的边按权从小到大排序,然后从第一条边开始,依边权递增的顺序查看每条边,并按下述方法连接两个不同的连通分支
  • 当查看到第 k k k条边 ( v , w ) (v , w) (v,w)时,如果端点 v v v w w w分别是当前两个不同的连通分支 T 1 T_{1} T1 T 2 T_{2} T2中的顶点时,就用边 ( v , w ) (v , w) (v,w) T 1 T_{1} T1 T 2 T_{2} T2连接成一个连通分支,然后继续查看第 k + 1 k + 1 k+1条边,如果端点 v v v w w w在当前的同一个连通分支中,就直接再查看第 k + 1 k + 1 k+1条边
  • 这个过程一直进行到只剩下一个连通分支时为止,此时这个连通分支就是 G G G的一棵最小生成树

时间复杂性

  • 当图的边数为 e e e时,Kruskal算法所需的时间是 O ( e log ⁡ e ) O(e \log{e}) O(eloge)
  • e = Ω ( n 2 ) e = \Omega(n^{2}) e=Ω(n2)是,Kruskal算法比Prim算法差,当 e = o ( n 2 ) e = o(n^{2}) e=o(n2)时,Kruskal算法比Prim算法好得多

Python实现

class Graph:
    def __init__(self, vertices):
        self.V = vertices  # 图中顶点的数量
        self.graph = []  # 存储图的边的列表

    def addEdge(self, u, v, w):
        self.graph.append([u, v, w])  # 添加边到图的边列表

    def find(self, parent, i):
        if parent[i] == i:  # 如果顶点 i 的根节点是自身, 则返回 i
            return i
        return self.find(parent, parent[i])  # 递归查找 i 的根节点

    def union(self, parent, rank, x, y):
        root_x = self.find(parent, x)  # 查找顶点 x 的根节点
        root_y = self.find(parent, y)  # 查找顶点 y 的根节点

        if rank[root_x] < rank[root_y]:  # 如果 x 的根节点的秩小于 y 的根节点的秩
            parent[root_x] = root_y  # 将 x 的根节点连接到 y 的根节点
        elif rank[root_x] > rank[root_y]:  # 如果 x 的根节点的秩大于 y 的根节点的秩
            parent[root_y] = root_x  # 将 y 的根节点连接到 x 的根节点
        else:  # 如果 x 和 y 的根节点的秩相同
            parent[root_y] = root_x  # 将 y 的根节点连接到 x 的根节点
            rank[root_x] += 1  # 增加 x 的根节点的秩

    def kruskalMST(self):
        result = []  # 存储最小生成树的边的列表
        i = 0  # 当前处理的边的索引
        e = 0  # 已经加入最小生成树的边的数量

        self.graph = sorted(self.graph, key=lambda x: x[2])  # 按照边的权重对图的边进行排序

        parent = []  # 存储顶点的父节点
        rank = []  # 存储顶点的秩
        for node in range(self.V):
            parent.append(node)  # 每个顶点的初始父节点是自身
            rank.append(0)  # 每个顶点的初始秩是 0

        while e < self.V - 1:  # 当最小生成树的边的数量小于 V - 1 时, 继续循环
            u, v, w = self.graph[i]  # 获取当前处理的边的源顶点、目标顶点和权重

            i += 1  # 增加边的索引

            x = self.find(parent, u)  # 查找 u 的根节点
            y = self.find(parent, v)  # 查找 v 的根节点

            if x != y:  # 如果 u 和 v 不在同一个连通分量中(不会形成环路)
                e += 1  # 增加已加入最小生成树的边的数量

                result.append([u, v, w])  # 将该边加入最小生成树的结果中

                self.union(parent, rank, x, y)  # 合并 u 和 v 所在的连通分量

        print('边\t\t权')

        for u, v, weight in result:
            print(f'{u} - {v}\t{weight}')  # 打印最小生成树的边和权重


g = Graph(5)

g.addEdge(0, 1, 2)
g.addEdge(0, 3, 6)
g.addEdge(1, 3, 8)
g.addEdge(1, 2, 3)
g.addEdge(1, 4, 5)
g.addEdge(2, 4, 7)
g.addEdge(3, 4, 9)

g.kruskalMST()
边		权
0 - 1	2
1 - 2	3
1 - 4	5
0 - 3	6

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

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

相关文章

听GPT 讲Rust源代码--src/tools(24)

File: rust/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs 在Rust源代码中的rust/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs文件是Clippy项目的一个规则&#xff0c;用于检查可能是误用或错误的Box引用情况。 Rust中的Box是一个堆分配的值的所有权…

京东员工:35岁,我只是年龄大了,又不是傻了残疾了,为啥找不到与3-5年经验者平等的面试机会?...

* 你好&#xff0c;我是前端队长&#xff0c;在职场&#xff0c;玩副业&#xff0c;文末有福利! 年龄大了&#xff0c;并不代表我们已经过时了。超过35岁的我们&#xff0c;面对着职场的冷风&#xff0c;经验丰富却常被误解。为什么年轻人能轻松得到的面试机会&#xff0c;到我…

【C语言刷题每日一题#牛客网BC68】——X形图案

问题描述 思路分析 首先根据输入的描述&#xff0c;多组输入需要将scanf放在循环中来实现 #include<stdio.h> int main() {int a 0;while (scanf("%d", &a) ! EOF){} } 完成了输入之后&#xff0c;再来分析输出——输出的是一个由“*”组成的对称的X形…

vue3项目 - 目录调整

省流 删除默认文件&#xff0c;修改代码 ---> 调整目录结构 ---> 添加全局样式和图片&#xff0c;安装预处理器 具体步骤&#xff1a; 1. 删除初始化的默认文件&#xff0c;修改剩余代码 清空 assets、components、stores、views文件夹里的文件&#xff0c;仅留核心文件…

【数据结构】布隆过滤器原理详解及其代码实现

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能AI、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐--…

神经网络:深度学习优化方法

1.有哪些方法能提升CNN模型的泛化能力 采集更多数据&#xff1a;数据决定算法的上限。 优化数据分布&#xff1a;数据类别均衡。 选用合适的目标函数。 设计合适的网络结构。 数据增强。 权值正则化。 使用合适的优化器等。 2.BN层面试高频问题大汇总 BN层解决了什么问…

智能优化算法应用:基于食肉植物算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于食肉植物算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于食肉植物算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.食肉植物算法4.实验参数设定5.算法结果6.…

Java之Synchronized与锁升级

Synchronized与锁升级 一、概述 在多线程并发编程中 synchronized 一直是元老级角色&#xff0c;很多人都会称呼它为重量级锁。但是&#xff0c;随着 Java SE 1.6 对 synchronized 进行了各种优化之后&#xff0c;有些情况下它就并不那么重了。 本文详细介绍 Java SE 1.6 中为…

DALL-E 2: Hierarchical Text-Conditional Image Generation with CLIP Latents

DALL-E 2 论文代码李沐讲DALLE 2方法 上图中,虚线的上半部分是CLIP的训练过程,虚线的下半部分描述的DALL-E 2的训练过程。CLIP训练 在训练时,将文本以及对应的图像分别输入到CLIP的文本编码器和图像编码器,然后得到输出的文本特征和图像特征,这两个特征就是一个正样本,该…

卷积神经网络基础与补充

参考自 up主的b站链接&#xff1a;霹雳吧啦Wz的个人空间-霹雳吧啦Wz个人主页-哔哩哔哩视频这位大佬的博客 https://blog.csdn.net/m0_37867091?typeblog CNN的历史发展&#xff1a; 这一点老师上课的时候也有讲到&#xff0c;BP的出现对CNN的发展至关重要 卷积的特性&#x…

MySQL中MVCC的流程

参考文章一 参考文章二 当谈到数据库的并发控制时&#xff0c;多版本并发控制&#xff08;MVCC&#xff09;是一个重要的概念。MVCC 是一种用于实现数据库事务隔离性的技术&#xff0c;常见于像 PostgreSQL 和 Oracle 这样的数据库系统中。 MVCC 的核心思想是为每个数据行维护…

(2021|CoRR,AugCLIP,优化)FuseDream:通过改进的 CLIP+GAN 空间优化实现免训练文本到图像生成

FuseDream: Training-Free Text-to-Image Generation with Improved CLIPGAN Space Optimization 公众&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要 1. 简介 2. CLIPGAN 文本到图…

ARM 汇编语言知识积累

博文参考&#xff1a; arm中SP&#xff0c;LR&#xff0c;PC寄存器以及其它所有寄存器以及处理器运行模式介绍 arm平台根据栈进行backtrace的方法-腾讯云开发者社区-腾讯云 (tencent.com) 特殊功能寄存器&#xff1a; SP&#xff1a; 即 R13&#xff0c;栈指针&#xff0c;…

DataProcess-VOC数据图像和标签一起进行Resize

VOC数据图像和标签一起进行Resize 参加检测比赛的时候&#xff0c;很多时候工业原始数据尺度都比较大&#xff0c;如果对数据不提前进行处理&#xff0c;会导致数据在加载进内存时花费大量的时间&#xff0c;所以在执行训练程序之前需要将图像提前进行预处理。对于目标检测的数…

基于SpringBoot + Vue的图书管理系统

功能概述 该图书管理系统提供了一系列功能&#xff0c;包括图书管理、图书类型管理、读者借阅归还图书、用户管理和重置密码等。 在图书管理功能中&#xff0c;管理员可以方便地进行图书信息的管理。他们可以添加新的图书记录&#xff0c;包括书名、作者、出版社、ISBN等信息&a…

DC-9靶机

目录 DC-9靶场链接&#xff1a; 首先进行主机发现&#xff1a; sqlmap注入&#xff1a; 文件包含&#xff1a; 端口敲门规则&#xff1a; hydra爆破&#xff1a; root提权&#xff1a; 方法一/etc/passwd&#xff1a; ​编辑 方法二定时任务crontab&#xff1a; DC-9靶…

Zookeeper入门

ZooKeeper 是一个开源的分布式协调架&#xff0c;主要用来解决分布式集群中应用系统的一致性问题 本质 分布式的文件存储系统(Zookeeper文件系统监听机制)&#xff0c;是一个基于观察者模式设计的分布式服务管理框架 zookeeper的数据结构 Zookeeper的层次模型称作Data Tree,…

Kubectl 部署有状态应用(下)

接上文 《Kubectl 部署有状态应用&#xff08;上&#xff09;》创建完StatefulSet后&#xff0c;本文继续介绍StatefulSet 扩展、更新、删除等内容。 StatefulSet 中的 Pod 验证序数索引和稳定的网络身份 StatefulSet 中的 Pod 具有唯一的序数索引和稳定的网络身份。 查看 …

外贸多语言电商系统的运作流程

外贸多语言电商系统的运作流程通常包括以下几个步骤&#xff1a; 1. 网站搭建和设计&#xff1a;首先需要搭建一个多语言电商网站&#xff0c;可以选择现有的电商平台或自行开发。网站设计应考虑不同语言和文化背景的用户需求&#xff0c;包括界面布局、导航结构、语言切换等。…

TLS 1.2详解

TSL由多个协议组成的两层协议集合&#xff0c;工作与应用层和传输层之间。 TLS协议包含两层协议&#xff1a;记录层协议&#xff08;TLS Record Protocol协议&#xff09;和 握手协议&#xff08;TLS Handshake Protocol协议&#xff09;&#xff0c;底层采用可靠传输协议&…