U4_2:图论之MST/Prim/Kruskal
文章目录
- 一、最小生成树-MST
- 生成MST策略
- 一些定义
- 思路
- 彩蛋
- 二、普里姆算法(Prim算法)
- 思路
- 算法流程
- 数据存储
- 分析
- 伪代码
- 时间复杂度分析
- 三、克鲁斯卡尔算法(Kruskal算法)
- 分析
- 算法流程
- 并查集-Find-set
- 伪代码
- 时间复杂度分析
一、最小生成树-MST
无向图,无环,所有点连通,边权重和最小
(没有权重标注就默认为1)

生成MST策略
- 从一个空图开始。
- 尝试一次添加一条边,始终确保所构建的保持无循环。
- 如果在添加了每条边之后,我们确定生成的图是某个最小生成树的子集,我们就完成了。
一些定义
集合 A A A是最小生成树 T T T的子集,当 A U ( u , v ) A\space U(u,v) A U(u,v)也是 M S T MST MST子集时, ( u , v ) (u,v) (u,v)是安全的。
切割 c u t cut cut: ( S , V − S ) (S,V-S) (S,V−S)
a a a c u t cut cut r e s p e c t s respects respects a a a s e t set set A A A o f of of e d g e s edges edges i f if if n o no no e d g e s edges edges i n in in A A A c r o s s e s crosses crosses t h e the the c u t cut cut.
An edge is a light edge crossing a cut if its weight is the minimumof any edge crossing the cut

思路
(S, V - S) be any cut of G that respects A
(u, v) be a light edge crossing the cut (S, V - S)Then, edge (u, v) is safe for A.
则 lt means that we can find a safe edge by
- first finding a cut that respects A
- then finding the light edge crossingthat cut
That light edge is a safe edge
彩蛋
本质上下面所要讲的Prim算法和Kruskal算法都是依据这个总思路来的,先分隔cut,然后根据cut找light edge,最后不断生成MST
二、普里姆算法(Prim算法)
思路
- 首先选择任意顶点r作为树的根。
- 当树不包含图中的所有顶点时:找到离开树的最短边并将其添加到树中。
这个思路可以想到,每次的cut就是选入作为顶点的集合 S S S和未选入的顶点 G − S G-S G−S
算法流程
数据存储
区分cut:最初始是空集,所有顶点被标记为白色,选入的顶点标记为黑色
利用优先队列存储
利用优先队列(小顶堆)去寻找 t h e the the l i g h e s t lighest lighest e d g e edge edge(相应函数如下)
3. I n s e r t ( u , k e y ) Insert(u, key) Insert(u,key):用键值key在Q中插入u。
4. u = E x t r a c t − m i n ( ) u = Extract- min() u=Extract−min():提取键值最小的项。
5. D e c r e a s e − K e y ( u , n e w − k e y ) Decrease-Key(u, new-key) Decrease−Key(u,new−key):将u的键值减小为new-key
利用 p r e d [ A ] pred[A] pred[A]去存储每个顶点的存储顺序
分析
t h e the the l i g h e s t lighest lighest e d g e edge edge本质上是在黑白分界点的这些边中寻找,因此每次更新都需要维护这些点( k e y key key)。
初始的时候设为 i n i f i n i t y inifinity inifinity,每次加入新顶点时就找到它的所有边判断是否比现在的key是否更小了,如果更小了就可以更新并且换前驱

伪代码
for u ∈ V docolor[u] ← white,key[u] ← +∞
end
key[u] ← 0,pred[r] ← null; //最开始的顶点
Q ← new PriQueue(V)
while Q is noempty dou ← Q.Extract-Min(); //the lighest edge for v ∈ adj[u] doif(color[u] ← white && w[u,v] < key[u]) thenkey[u] ← w[u,v]Q.decrease-Key(v,key[u]) pred[v] ← uendendcolor[u] ← black
end
时间复杂度分析
创建优先队列 O ( V l o g V ) O(VlogV) O(VlogV),每次循环 E x t r a c t − M i n Extract-Min Extract−Min为 l o g ( V ) log(V) log(V),总共V个顶点,总时间复杂度为 O ( V l o g V ) O(VlogV) O(VlogV)。每次循环 D e c r e a s e − K e y Decrease-Key Decrease−Key为 O ( l o g V ) O(logV) O(logV),因为循环内每次更新都是针对边来说,所有边都遍历一遍,因此循环内总时间复杂度为 O ( E l o g V ) O(ElogV) O(ElogV),总时间复杂度为 T ( n ) = O ( ( V + E ) l o g V ) = O ( E l o g V ) T(n)=O((V+E)logV)=O(ElogV) T(n)=O((V+E)logV)=O(ElogV)
三、克鲁斯卡尔算法(Kruskal算法)
分析
- 从一个空图开始。
- 尝试一次添加一条边,始终确保所构建的保持无循环。.
- 如果我们在每一步都确定生成的图是某个最小生成树的子集,我们就完成了。
与Prim的算法生长一棵树不同,Kruskal的算法生长一组树(森林)。
最初,这个森林只由顶点组成(没有边)。
在每一步中,添加不产生循环的权重最小的边。
继续直到森林“合并”成一棵树。
本质上,也是继承于一说的主算法:
设A为Kruskal算法选择的边集,设(u, v)为下一步要添加的边。这足以说明这一点:
t h e r e there there i s is is a a a c u t cut cut t h a t that that r e s p e c t s respects respects A A A
( u , v ) (u, v) (u,v) i s is is t h e the the l i g h t light light e d g e edge edge c r o s s i n g crossing crossing t h i s this this c u t cut cut

算法流程
- 刚开始 A A A为空集, F F F存入所有边并且从小到大排序,
- 在F中选择一条权值最小的边e,检查将e加到A上是否形成一个循环。
构成循环,则从F移除
不构成循环,则从F添加进A - F为空集时停止操作
现在有个问题,怎么才能不形成环呢,
在框架算法的每一步中, ( V , A ) (V,A) (V,A)都是非循环的,因此它是一个森林,一个顶点延申两条枝干,且枝干之间没有路径,这样就是森林。因此:
如果 u u u和 v v v在同一棵树中,则将边 u , v {u,v} u,v添加到A中创建一个循环。
如果 u u u和 v v v不在同一棵树中,那么将边 u , v {u,v} u,v添加到 A A A中不会创建一个循环。
根据这个性质,如果一条边被选中,它的两个端点若在一个树上,那么再将这条边添加进树时,肯定会形成环,根据这一性质,我们可以维护并查集去判断是否成环
并查集-Find-set
本质上,并查集就是一个个树集合,每个元素都唯一指向它的父亲,根节点父亲就是子集,因此每棵树的唯一标识就是根节点。如果两个元素唯一标识一样,那它们就在一棵树上。

j u d g e judge judge f i n d − s e t ( u ) find-set(u) find−set(u) = = == == f i n d − s e t ( v ) find-set(v) find−set(v),维护 f i n d − s e t find-set find−set过程如下:
- C r e a t e − s e t u ) Create-set u) Create−setu):创建包含单个元素 u u u的集合。 O ( 1 ) O(1) O(1)
x.parent ← x
- F i n d − s e t ( u ) Find-set (u) Find−set(u):查找包含元素u的集合(假设每个集合都有唯一的ID,后面可知是树的根节点)。 O ( l o g n ) O(logn) O(logn)
while x != x.parent dox ← x.parent
end
- U n i o n ( u , v ) Union(u, v) Union(u,v):将分别包含u和v的集合归并为一个公共集合。(当判断完不会形成环后,可以合并). O ( l o g n ) O(logn) O(logn)(找树的根节点费时,其他都是 O ( 1 ) O(1) O(1)时间)
注意当我们将两棵树合并在一起时,我们总是将高树的根作为矮树的父树。不然会很畸形,费时。
如果两棵树有相同的高度,我们选择第一棵树的根指向第二棵树的根。树的高度增加了1(根节点+被合并的子树,因此高度+1)。其他情况下树的高度都是不变的。
a ← Find-Set(x)
b ← Find-Set(y)
if a.height <= b.height thenif a.height is equal to b.height thenb.hright++;enda.parent ← b
end
elseb.parent ← a
end
伪代码
sort E in increasing order by weight w;
A ← {}
for u ∈ V doCreate-Set(u);
end
for ei ∈E do //ei两个端点为ui,viif(find-set(ui)!=find-set(vi)) thenadd {ui,vi} to AUnion(ui,vi)end
end
return
时间复杂度分析
排序用时 O ( E l o g E ) O(ElogE) O(ElogE), c r e a t e − s e t create-set create−set用时 O ( V ) O(V) O(V),循环次数是边的次数 E E E,每次循环 u n i o n union union花费 l o g ( V ) log(V) log(V),总时间复杂度 O ( E l o g V ) O(ElogV) O(ElogV),因此总花费 T ( n ) = O ( E l o g E ) T(n)=O(ElogE) T(n)=O(ElogE)(边比顶点多,取大的)
相关文章:
U4_2:图论之MST/Prim/Kruskal
文章目录 一、最小生成树-MST生成MST策略一些定义 思路彩蛋 二、普里姆算法(Prim算法)思路算法流程数据存储分析 伪代码时间复杂度分析 三、克鲁斯卡尔算法(Kruskal算法)分析算法流程并查集-Find-set 伪代码时间复杂度分析 一、最…...
springboot 注解@JsonInclude
修饰 实体属性or实体类 //枚举值:ALWAYS,NON_NULL,NON_ABSENT,NON_EMPTY,NON_DEFAULT,CUSTOM,USE_DEFAULTS JsonInclude(Include.NON_EMPTY)//将该标记放在属性上,如果该属性为NULL则不参与序列化 //如果放在类上边,那对这个类的全部属性起作用 Inclu…...
Python 中文完整教程目录
Python 教程 Python 是一门易于学习、功能强大的编程语言。它提供了高效的高级数据结构,还能简单有效地面向对象编程。Python 优雅的语法和动态类型以及解释型语言的本质,使它成为多数平台上写脚本和快速开发应用的理想语言。 Python 官网(…...
C/C++---------------LeetCode第35. 搜索插入位置
插入的位置 题目及要求二分查找在main内使用 题目及要求 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: …...
网络安全--基于Kali的网络扫描基础技术
文章目录 1. 标准ICMP扫描1.1使用Ping命令1.1.1格式1.1.2实战 1.2使用Nmap工具1.2.1格式1.2.2实战1.2.2.1主机在线1.2.2.2主机不在线 1.3使用Fping命令1.3.1格式1.3.2实战 2. 时间戳查询扫描2.1格式2.2实战 3. 地址掩码查询扫描3.1格式3.2实战 2. TCP扫描2.1TCP工作机制2.2TCP …...
C语言——求π的近似值
#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> #include<math.h> int main() {int s;double n,t,pi;t1;pi0;n1.0;s1;while (fabs(t)>1e-6){pipit; nn2; s-s; ts/n;}pipi*4;printf("pi%lf\n",pi);return 0; }这里是求小数点后6位——1e-6&#…...
如何使用ffmpeg转换图片格式
ffmpeg简介与图片格式介绍 windows安装ffmpeg,从如下网站下载release版本 https://www.gyan.dev/ffmpeg/builds/ ffmpeg 6.1版本仍然不支持heic的图片格式,未来可能会支持,具体见该issue: https://trac.ffmpeg.org/ticket/6521 …...
11 动态规划解最后一块石头的重量II
来源:LeetCode第1049题 难度:中等 描述:有一堆石头,用证书数组stones表示,其中stones[i]表示第i块石头的重量,每一回合,从中选出任意两块石头,然后将他们放在一起粉碎,…...
LeetCode算法题解(动态规划,股票买卖)|LeetCode121. 买卖股票的最佳时机、LeetCode122. 买卖股票的最佳时机 II
一、LeetCode121. 买卖股票的最佳时机 题目链接:121. 买卖股票的最佳时机 题目描述: 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一…...
python实验3 石头剪刀布游戏
实验3:石头剪刀布游戏 一、实验目的二、知识要点图三、实验1. 石头剪刀布2. 实现大侠个人信息 一、实验目的 了解3类基本组合数据类型。理解列表概念并掌握Python中列表的使用。理解字典概念并掌握Python中字典的使用。运用jieba库进行中文分词并进行文本词频统计。…...
米贸搜|如何设置 Facebook 转换 API + 事件重复数据删除
Facebook Pixel 可让您跟踪用户在您网站上的行为、收集再营销受众并创建相似对象。如果 Facebook 像素实现正确,它将向 FB 机器学习算法提供相关信息。 FB ML 将使用像素数据向最有可能转化的人展示您的广告。 几年来,我们可以通过 JavaScript 代码、应…...
python每日一题——11滑动窗口最大值
题目 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值 。 示例 1: 输入:nums [1,3,-1,-3,5,3,6,7], k 3…...
【C++ 程序设计入门基础】- 第3节-循环结构01
目录 循环结构 一、for 语句 for 循环案例 输入一个整数n,输出1~n的所有整数。 编译运行,查看输出结果 编译调试 for 循环结构语义分析 二、beak 语句 三、continue 语句 案例1: 案例2: 案例3: 循环…...
人工智能原理复习--知识表示(一)
文章目录 上一篇知识概述命题逻辑谓词逻辑谓词逻辑的应用 下一篇 上一篇 人工智能原理复习–绪论 知识概述 知识就是人类认识自然界的精神产物,是人类进行智能活动的基础。 是经过加工的信息,包括事实、信念和启发式规则。 分类: 按作用可…...
网络运维与网络安全 学习笔记2023.11.28
网络运维与网络安全 学习笔记 第二十九天 今日目标 OSPF汇总之域间路由、OSPF汇总之外部路由、OSPF链路认证 OSPF安全认证之区域认证、OSPF虚链路 OSPF汇总指域间路由 项目背景 企业内网运行多区域的OSPF网络,在R1 上存在多个不稳定的链路 R1上的不稳定链路&a…...
Rust开发——数据对象的内存布局
枚举与Sized 数据 一般数据类型的布局是其大小(size)、对齐方式(align)及其字段的相对偏移量。 1. 枚举(Enum)的布局: 枚举类型在内存中的布局通常是由编译器来确定的。不同的编译器可能有不…...
mySQL踩坑记录
1.MYSQL Workbench-8.0.27.1出现"Exception: Current profile has no WMI enabled"错误的解决方法 MYSQL Workbench-8.0.27.1出现“Exception: Current profile has no WMI enabled“错误的解决方法_赛风扥的博客-CSDN博客 C:\Program Files\MySQL\MySQL Workbench …...
【Java】使用 IDEA 快速生成 SpringBoot 模块
项目目录下新建 module 模块 在 pom.xml 更改为 spring initializr 配置之后的 pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchem…...
2023网络安全产业图谱
1. 前言 2023年7月10日,嘶吼安全产业研究院联合国家网络安全产业园区(通州园)正式发布《嘶吼2023网络安全产业图谱》。 嘶吼安全产业研究院根据当前网络安全发展规划与趋势发布《嘶吼2023网络安全产业图谱》调研,旨在进一步了解…...
一则 MongoDB 副本集迁移实操案例
文中详细阐述了通过全量 增量 Oplog 的迁移方式,完成一套副本集 MongoDB 迁移的全过程。 作者:张然,DBA 数据库技术爱好者~ 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。 本文约 900…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
