1024 你学算法了吗?

news2024/11/20 2:42:09


🎈 作者:Linux猿

🎈 简介:CSDN博客专家🏆,华为云享专家🏆,Linux、C/C++、云计算、物联网、面试、刷题、算法尽管咨询我,关注我,有问题私聊!

🎈 关注专栏: 数据结构和算法成神路【精讲】优质好文持续更新中……🚀🚀🚀

🎈 欢迎小伙伴们点赞👍、收藏⭐、留言💬


目录

一、什么是最小生成树?

二、克鲁斯卡尔(Kruskal) 算法

2.1 Kruskal 算法起源

2.2 算法原理

2.3 实例演示

2.4 算法模板

2.5 算法复杂度

2.5.1 时间复杂度

2.5.2 空间复杂度

三、真题练习

四、总结


 这篇文章来讲解下图论算法之 克鲁斯卡尔(Kruskal)克鲁斯卡尔(Kruskal)通常用于求解最小生成树,求解最小生成树的算法还有普里姆(Prim)算法和Boruvka算法,下面就来看下克鲁斯卡尔(Kruskal)算法吧!

🔶🔶🔶🔶🔶 我是华丽的分割线 🔶🔶🔶🔶🔶

一、什么是最小生成树?

在介绍具体算法之前,先来说下什么是最小生成树

假设在 n 个城市之间铺设网络,使得 n 个城市能够互相通信,已知任意两个城市之间铺设网络的费用,如何使得费用最小?

很显然,只需要铺设 n - 1 条线路即可使得 n 个城市能够互相通信。(n 个点构成一个连通图至少需要 n - 1 条边)。

最小生成树是指构造连通网的最小代价生成树,所以最小生成树具有 n 个顶点 n - 1 条边。

构造一个连通网的最小生成树通常有三大算法:普里姆(Prim)算法、克鲁斯卡尔(Kruskal)以及Boruvka算法。

本篇文章来介绍一下 克鲁斯卡尔(Kruskal)算法,普里姆(Prim)算法已经在上一篇文章中讲解过文章链接。

🔶🔶🔶🔶🔶 我是华丽的分割线 🔶🔶🔶🔶🔶

二、克鲁斯卡尔(Kruskal) 算法

2.1 Kruskal 算法起源

克鲁斯卡尔是美国人(数学家、统计员、电脑科学家和心理测量师)。1956年,克鲁斯卡尔提出了 Kruskal 算法,它是一个贪心算法,主要用于求解最小生成树

2.2 算法原理

假设图为 G,顶点集合为 V,边的集合为 E,按照克鲁斯卡尔(Kruskal)算法求解最小生成树的步骤如下所示:

(1)首先,建立新图 G1,G1 的顶点集合为 V1,V1等于原图 G 顶点集合 V,边的集合设为 E1,E1 = {},集合为空;

(2)将原图 G 中所有的边按权值从小到大排序;

(3)从排序后的权值中从小到大依次选择,选择当前排序后权值最小的边(u, v),如果边(u,v)的两个顶点在新图 G1 中连接两个不同的连通分量,则将这条边添加到新图 G1 边的集合 E1 中;

(4)重复步骤(3),直到原图 G 中的所有边都选择完,或者新图 G1 中的所有顶点都在同一个连通分量中。

2.3 实例演示

下面通过一个实例演示进行说明,假设无向图G如下所示。

图1 无向图 G

在上图中,包括四个顶点 A、B、C、D 以及相互连接的边,各个边上的数字表示边的权重,上面是一个无向图。

其中,V = {A, B, C, D}, E = {AB, AC, AD, BC, BD, CD}

(1)初始时 V1 = {A, B, C, D}E1 = {},建立新图G1 如下所示。

图2 初始化无向图 G1

在经过初始化后,无向图 G1 中已经包含原图 G 所有顶点,但是,边的集合 E1 为空,即:V1 = {A,B, C, D},E1 = {}。

并将原图 G 的边按照权重从小到大排序,如上图中所示。

(2)从排序后的边从小到大开始选择,选择边(C, D),因为 C 和 D 两个顶点在新图 G1 中属于不同的连通分量,所以加入到新图 G1 中,加入后图 G1 如下所示:

图3 加入边(C,D)

新图 G1的边的集合 E1 = { CD }

(3)按照排序后边的大小,选择边(B, C),因为顶点 B 和顶点 C 属于不同的连通分量,所以将(B,C)加入到无向图G1中,如下所示:

图4 加入(B,C)

 新图 G1 的边的集合 E1 = { CD,BC }。

(4)按照排序后边的权重大小,选择边(B, D),因为顶点 B 和 顶点 D 属于相同的连通分量,所以(B,D)不能加入到无向图 G1 中。

(5)按照排序后边的权重大小,选择边(A, D),因为顶点 A 和 顶点 D 属于不同的连通分量,所以将(A,D)加入到无向图 G1 中,如下所示:

图5 加入边(A, D)

 新图G1 的边的集合 E1 = { CD,BC,AD }。

(6)加入边(A, D)后,已经形成了一棵最小生成树,通过 n - 1 条边,连接了 n 个顶点,可以发现剩余的两条边(A,B)和 (A, C)如果尝试加入,顶点 A 和顶点 B 属于相同的连通分量,顶点 A 和顶点 C 属于相同的连通分量,所以都不能加入到图 G1 中。

2.4 算法模板

下面是克鲁斯卡尔(Kruskal)算法的算法模板,通过并查集查看每次加入边的两个顶点是否为同一个连通分量,通过 sort 算法按照权重从小到大排序。

#include<iostream>
#include<algorithm>
using namespace std;
const int SIZE = 1e5 + 5;

int n, m; // n 表示顶点的个数,m 表示边的个数
int father[SIZE];   //记录节点的父节点
// 存储图的边
struct Edge
{
    int u; // 边的顶点
    int v; // 边的顶点
    int w; // 边的权重
}T[SIZE];

/**
 * 通过并查集查找父节点
 */
int find(int u)
{
    if (father[u] != u) {
        father[u] = find(father[u]);
    }
    return father[u];
}

/**
 * 通过 kruskal 计算最小生成树
 * 返回最小生成树的权值和
 */
int kruskal()
{
    //初始化并查集
    for (int i = 1; i <= n; i++)
        father[i] = i;

    //按照边的权值大小排序,使用了 lambda 表达式
    sort(T, T + m, [](const Edge& a, const Edge& b){ return a.w < b.w;});

    //按照权值从小到大选择
    int x, y;
    int num = 0; // 用于统计加入边的个数,可以提前结束下面的 for 循环
    int ans = 0;
    for (int i = 0; i < m; ++i) {
        x = find(T[i].u);
        y = find(T[i].v);
        if (x != y) { // 说明不是一个连通分量
            father[x] = y;
            ans += T[i].w;
            num++;
        }
        if(num == n - 1) break; // 表示新图 G1 中已经有 n - 1 条边,构成了最小生成树
    }
    return num == n - 1 ? ans : -1;
}

/**
 * 获取输入
 * n 表示顶点个数
 * m 表示边的个数
 */
void input() {
    cin>>n>>m;
    //输入 m 条边,其中,u 和 v表示顶点,w 表示边(u, v)的权重
    for(int i = 0; i < m; ++i) {
        cin>>T[i].u>>T[i].v>>T[i].w;
    }
}

/**
 测试数据:
 4 6
 1 2 10
 1 3 21
 1 4 9
 2 3 5
 2 4 6
 3 4 2
 输出结果:16
 选中的边为:(3, 4)、(2, 3)、(1, 4)
**/

int main()
{
    input();
    cout<<kruskal()<<endl;
    return 0;
}

2.5 算法复杂度

2.5.1 时间复杂度

时间复杂度为:O(mlogm)

在上述代码中,耗费时间的操作主要有for 循环初始化 father 数组、sort 排序以及对 m 条边进行 for 循环遍历,时间复杂度分别为:O(n)(for循环 n 时间复杂度)O(mlogm)(快排时间复杂度),O(m)(for 循环 m 时间复杂度),因为这三个时间是串行的,一般取大者为算法的时间复杂度,所以时间复杂度为O(mlogm)。

2.5.2 空间复杂度

空间复杂度为:O(n + m)

在上述代码中,使用 father 数组存储 n 个元素的父节点,使用 T 数组存储 m 条边和权重信息,所以时间复杂度为 O(n + m)。

🔶🔶🔶🔶🔶 我是华丽的分割线 🔶🔶🔶🔶🔶

三、真题练习

理解了克鲁斯卡尔(Kruskal)算法后,可以练习下下面两个题目。

1. POJ 2377 Bad Cowtractors

2. POJ 1258 Agri-Net

🔶🔶🔶🔶🔶 我是华丽的分割线 🔶🔶🔶🔶🔶

四、总结

最小生成树算法主要用于求解连通图最小权值的情况,而 克鲁斯卡尔(Kruskal)算法用于稠密图的情况,因为克鲁斯卡尔(Kruskal)算法是以边为基础构造最小生成树的。


🎈 感觉有帮助记得「一键三连支持下哦!有问题可在评论区留言💬,感谢大家的一路支持!🤞猿哥将持续输出「优质文章回馈大家!🤞🌹🌹🌹🌹🌹🌹🤞


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

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

相关文章

JUC - 多线程之 单例模式(八)

单例模式&#xff08;Singleton Pattern&#xff09;是一种非常简单的设计模式之一&#xff0c;当我们使用的对象要在全局唯一时就需要用到该模式&#xff0c;以保证对象的唯一性。除此之外&#xff0c;还能避免反复的实例化对象&#xff0c;减少内存开销 单例类提供了一种访问…

踩坑记录——USB键盘睡眠唤醒

踩坑记录——USB键盘睡眠唤醒 目录踩坑记录——USB键盘睡眠唤醒前言1 USB远程睡眠唤醒要注意的几个点2 MCU唤醒之后引起USB异常的几个点结束语前言 前段时间我用一个国产MCU实现了雷蛇键盘的效果&#xff0c;按键支持十键无冲&#xff0c;RGB灯支持单控任意一个灯任意一种颜色…

SpringAMQP (RabbitMQ五种模式 消息转换器)

一、简化Hello World模型实现步骤演示 代码步骤演示如下所示&#xff1a; 消息提供者publisher代码简化&#xff1a; 消息消费者consumer代码简化&#xff1a; 二、Work Queue 工作队列模型 消息提供者代码如下所示&#xff1a; 消息消费者代码如下所示&#xff1a; 消息…

SpringCloudAlibaba【六】微服务架构下的秒杀案例

背景 分布式微服务中的秒杀是怎么实现的呢&#xff1f;接着看下去吧 我们实现一个秒杀微服务&#xff0c;流程逻辑如下 项目搭建 MySQL create database if not exists demo;use demo;drop table if exists skill_goods;create table if not exists skill_goods (id bigint…

1024程序员节|【MySQL从入门到精通】【高级篇】(二十七)外连接和内连接如何进行查询优化呢?join的原理了解一波

您好&#xff0c;我是码农飞哥&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f4aa;&#x1f3fb; 1. Python基础专栏&#xff0c;基础知识一网打尽&#xff0c;9.9元买不了吃亏&#xff0c;买不了上当。 Python从入门到精通 ❤️ 2.网上优质的Python题库很少…

[面试宝典] Linux常见命令及面试题

前言&#xff1a; &#x1f604;作者简介&#xff1a;小曾同学.com,小伙伴们也可以叫我小曾&#xff0c;一个致力于测试开发的博主⛽️ 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。&#x1f60a; 座右铭&#xff1a;…

C语言 - 你一定能看懂的扫雷万字详解(加入了递归展开和手动标雷的功能)

C语言之扫雷详解&#xff08;包含递归展开和手动标雷功能&#xff0c;非常强大&#xff01;&#xff09; 文章目录一.写在前面二.效果展示三.整体逻辑四.详解1.进入主函数&#xff0c;打印菜单&#xff0c;玩家作出选择2.定义棋盘的数组并进行赋值3.棋盘的展示4.随机布雷5.开始…

前端开发入门--html--Flask

快速开发网站 pip install flaskfrom flask import Flaskapp Flask(__name__)# 创建了网址 /show/info 和 函数index 的对应关系 # 以后用户在浏览器上访问 /show/info&#xff0c;网站自动执行 index app.route("/show/info") def index():return "中国联通&…

TPH-YOLOv5 | 基于Transformer的YOLOv5小目标检测器 | 四头加注意力

论文地址&#xff1a;https://arxiv.org/pdf/2108.11539.pdf 项目地址&#xff1a;https://github.com/cv516Buaa/tph-yolov5 在无人机捕获的场景中进行对象检测是最近的一项热门任务。由于无人机总是在不同的高度航行&#xff0c;物体尺度变化剧烈&#xff0c;给网络优化带来…

NMEA协议解析

文章目录一、NMEA0183协议1、NMEA基本框架2、常用语句1&#xff09;GNGGA2&#xff09;GNGLL3&#xff09;GNGSA4&#xff09;GPGSV5&#xff09;GNRMC6&#xff09;GNVTG7&#xff09;GNZDA8&#xff09;PAIRCLK等二、异或校验和代码1、网址在线计算BCC2、BCC校验和代码一、NM…

Java语言中的异常处理

异常处理 在java语言中&#xff0c;很机智的将异常作为对象来处理&#xff0c;而且定义一个基类java.lang.Throwable作为所有异常类的父类。在这许多类中一般分为两大类&#xff1a; 错误类(Error)和异常类&#xff08;Expception&#xff09;。 如图&#xff1a; 注&#xf…

iNOF在现实网络中的运用,以带反射器的iONF为例

定义 iNOF&#xff08;Intelligent Lossless NVMe Over Fabric&#xff0c;智能无损存储网络&#xff09;是指通过对接入主机的快速管控&#xff0c;将智能无损网络应用到存储系统&#xff0c;实现计算和存储网络融合的技术。 目的 网络转发设备用于传输流量&#xff0c;不同类…

竞争不是内卷,用头脑学习,而非时间

文章目录 用头脑学习&#xff0c;而非时间 前言 一、自由竞争不是内卷 二、内卷都在哪些行业 三、高效学习来大数据梦想联盟 用头脑学习&#xff0c;而非时间 前言 大多数人不懂&#xff0c;不会&#xff0c;不做&#xff0c;才是你的机会&#xff0c;你得行动&#xff…

【Queue】- 从源码分析ArrayDeque及其常用方法

文章目录概述ArrayDeque基础知识ArrayDeque内部结构ArrayDeque的构造方法ArrayDeque的扩容操作ArrayDeque常用方法将ArrayDeque作为双端队列使用时public void addFirst(E e)public void addLast(E e)public boolean offerFirst(E e)public boolean offerLast(E e)public E pol…

动态SLAM论文归纳

持续更新&#xff0c;持续更新 2022 Multi-modal Semantic SLAM for Complex Dynamic Environments 作者&#xff1a;Han Wang, Jing Ying Ko and Lihua Xie, Fellowcode&#xff1a;https://github.com/wh200720041/MMS_SLAM视频&#xff1a;https://www.youtube.com/watch…

web自动化测试——入门篇01

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…

并发编程中的原子性,可见性,有序性问题

前言&#xff1a;大家好&#xff0c;我是小威&#xff0c;24届毕业生&#xff0c;在一家满意的公司实习。本篇文章是关于并发编程中出现的原子性&#xff0c;可见性&#xff0c;有序性问题。 本篇文章记录的基础知识&#xff0c;适合在学Java的小白&#xff0c;也适合复习中&am…

PyTorch(三)TensorBoard 与 Transforms

文章目录Log一、TensorBoard1. TensorBoard 的安装2. SummaryWriter 的使用① add_scalar() 的使用a. 参数说明b. 函数使用c. 使用 Tensorboard② add_image() 的使用a. 参数说明b. 使用 numpy.array() 对 PIL 图片进行转换c. 使用函数d. 改变 global_step二、Transforms1. Tra…

数据结构 | 时间复杂度与空间复杂度

… &#x1f333;&#x1f332;&#x1f331;本文已收录至&#xff1a;数据结构 | C语言 更多知识尽在此专栏中&#xff01; &#x1f389;&#x1f389;&#x1f389;欢迎点赞、收藏、关注 &#x1f389;&#x1f389;&#x1f389;文章目录&#x1f333;前言&#x1f333;正…

【C++初阶】类和对象(二)

大家好我是沐曦希&#x1f495; 类和对象1.类的6个默认成员函数2.构造函数2.1 概念2.2 特性3.析构函数3.1 概念3.2 特性4.拷贝构造函数4.1 概念4.2 特征1.类的6个默认成员函数 空类&#xff1a;类中一个成员都没有 可是空类真的什么都没有吗&#xff1f; 并不是&#xff0c;任…