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

news/2024/9/22 10:59:23/

文章目录

    • @[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的一棵最小生成树

Python_36">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 的根节点是自身, 则返回 ireturn ireturn 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)  # 每个顶点的初始秩是 0while 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

时间复杂性

  • 当图的边数为 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算法好得多


http://www.ppmy.cn/news/1457996.html

相关文章

OpenAI 最佳平替,使用 Promptulate 增强你的AI能力

&#x1f496; Brief&#xff1a;大家好&#xff0c;我是Zeeland。Tags: 大模型创业、LangChain Top Contributor、算法工程师、Promptulate founder、Python开发者。&#x1f4dd; CSDN主页&#xff1a;Zeeland&#x1f525;&#x1f4e3; 个人说明书&#xff1a;Zeeland&…

网络安全之ACL

ACL&#xff1a;访问控制列表——控制列表&#xff08;策略列表&#xff09;&#xff0c;是一个控制工具。 功能&#xff1a;&#xff01;、定义感兴趣路由&#xff08;控制层面&#xff09;。2、定义感兴趣流量&#xff08;数据层面&#xff09;。 例如&#xff1a; 假设在该…

Python 二级考试刷什么题?

Python 二级考试是一种测试 Python 编程技能的标准化考试&#xff0c;旨在评估考生对 Python 语言的掌握程度以及其在编程实践中的应用能力。 该考试通常包含一系列的选择题和编程题&#xff0c;涵盖 Python 的基础知识、数据结构与算法、面向对象编程、文件操作、异常处理、模…

传神论文中心|本周人工智能领域论文推荐

在人工智能领域的快速发展中&#xff0c;我们不断看到令人振奋的技术进步和创新。近期&#xff0c;开放传神&#xff08;OpenCSG&#xff09;社区发现了一些值得关注的成就。在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;已经成为了许多领域的核心驱动力。o…

微机控制电子式万能试验机WDW-5B

一.项目简介&#xff1a; 国内微机控制电子式万能试验机起步于90年代初&#xff0c;为提高企业产品的技术水平&#xff0c;公司先后引进国外先进技术&#xff0c;使公司的产品技术水平跃上了一个新的台阶。 二.使用领域&#xff1a; 该产品广泛用于金属、非金属材料的拉、压…

深入浅出带你搞懂-MOSFET栅极电阻

一、MOSFET简介 MOSFET是金属&#xff08;metal&#xff09;—氧化物&#xff08;oxide&#xff09;—半导体&#xff08;semiconductor&#xff09;场效应晶体管&#xff0c;属于电压控制电流型元件&#xff0c;是开关电路中的基本元件&#xff0c;其栅极&#xff08;G极&…

E. Monotonic Renumeration

链接 : Problem - E - Codeforces 思路 : 区间合并 快速幂 对于a[0],那么从第一个a[0],到最后一个a[0]这个区间内所有b值全部为b[0] 0,以此类推&#xff0c;对于其他值也是一样&#xff1b; 例如对于[1 , 2 , 1 , 2 , 3] 首先b[0] 0(题目要求) &#xff0c; 然后因为…

支持LLM的Markdown笔记;ComfyUI-HiDiffusion图片生成和对图像进行高质量编辑

✨ 1: ComfyUI-HiDiffusion ComfyUI-HiDiffusion是一个为HiDiffusion技术使用而定制的节点。HiDiffusion技术是专门用于在计算机视觉和图像处理中生成和改进图片质量的先进算法。该技术通常应用于图像的超分辨率、去噪、风格转换等方面。 ComfyUI-HiDiffusion的主要特点包含提…