数据结构与算法笔记7:最小生成树-Prim和Kruskal算法

news2024/9/29 9:58:30

常用的最小生成树的算法主要有两种,一种是Prim算法,一种是Kruskal算法。题目链接:KamaCoder 53. 寻宝(第七期模拟笔试)
在这里插入图片描述
在这里插入图片描述
这里假设有V个节点,因为我们的节点的标号是1~V,这样我们直接使用标号作为索引,不用额外的+1或者-1操作。

1. Prim算法

Prim算法基本的思路是按点来遍历,适合点比较少边比较多的稠密图,步骤是:

  1. 初始化minDist(最小生成树到每个节点的最小值),grid(图里的边权),visited(是否加入最小生成树),我们把minDist设置为长度V+1,把grid设置为长和宽分别为V+1和V+1,visited长度也是V+1。
  • minDist初始化,初始化均为一个很大的值,这里的节点的数量小于等于10000,设置为10001:
vector<int> minDist(V+1, 10001);
  • grid初始化,一开始我们设置为一个很大的值,表示任意的两个点u和v是不可达的,因为我们后面要计算节点到最小生成树的最小值,所以我们初始化为最大值,后面求最小值才是有效的:
vector<vector<int>> grid(V+1, vector<int>(V+1, 10001));
  • visited初始化,一开始所有的节点都是没有访问过的,所以我们初始化为0,表示没有访问过,后面访问过加入了最小生成树以后我们要把节点visited对应的节点的值设置为1
vector<int> visited(V+1, 0);
  1. 求离最小生成树最近的点cur,定义初始距离minVal = INT_MAX,然后遍历所有的节点 j ∈ [ 1 , V ] j\in[1,V] j[1,V],如果 m i n V a l < m i n D i s t [ j ] minVal<minDist[j] minVal<minDist[j],minVal赋值为minDist[j],cur赋值为j,所有节点遍历结束以后,我们找到了离最小生成树最近的那个点,第一个找到的cur其实是1:
int minVal = INT_MAX;    
int cur = -1;
for (int j = 1; j <= V; ++j)
{
    if (!visited[j] && minDist[j] < minVal) // j不在最小生成树中并且j节点到最小生成树的距离比minVal更小
    {
        minVal = minDist[j];
        cur = j;
    }
}
  1. 把节点cur加入到最小生成树里,其实就是将visited[cur]标记为1
visited[cur] = 1;
  1. 更新cur加入最小生成树以后得minDist:遍历所有节点 j ∈ [ 1 , V ] j\in[1,V] j[1,V],如果grid[cur][j] < minDist[j],那么更新minDist[j]为grid[cur][j]:
for (int j = 1; j <= V; ++j)
{
    if (!visited[j] && grid[cur][j] < minDist[j])// j不在最小生成树中并且cur到j的距离比j到最小生成树上一次距离小
        minDist[j] = grid[cur][j];
}

因为一个最小生成树有V个节点我们需要添加V-1条边,那么我们就需要遍历V-1次(minDist更新V-1次,回想我们的更新minDist使用了grid[cur][j],表示从cur到j,因为第一个顶点是没有父亲节点的,所以第一个顶点对应的minDist[1]是不会更新的,j不会为1,更新的minDist的索引是从2到V的),那我们就可以写出完整的代码了:

#include <iostream>
#include <climits>
#include <vector>
using namespace std;

int main()
{
    int V, E;
    
    cin >> V >> E;

    vector<int> visited(V+1, 0);
    vector<int> minDist(V+1, 10001);
    
    vector<vector<int>> grid(V+1, vector<int>(V+1, 10001));
    for (int i = 0; i < E; ++i)
    {
        int x, y, v;
        cin >> x >> y >> v;
        grid[x][y] = v;
        grid[y][x] = v;
    }
    
    
    for (int i = 1; i < V; ++i)
    {
        int minVal = INT_MAX;    
        int cur = -1;
        for (int j = 1; j <= V; ++j)
        {
            if (!visited[j] && minDist[j] < minVal)
            {
                minVal = minDist[j];
                cur = j;
            }
        }
        
        visited[cur] = 1;
        
        for (int j = 1; j <= V; ++j)
        {
            if (!visited[j] && grid[cur][j] < minDist[j])
                minDist[j] = grid[cur][j];
        }
    }
    int ans = 0;
    for (int i = 2; i <= V; ++i)
        ans += minDist[i];
    cout << ans << endl;
}

Kruskal算法

Prim算法基本的思路是按边来遍历,适合边比较少点比较多的稀疏图,步骤是:

  1. 对所有的边权排序,小的边权排前面,大的排后面
  2. 遍历所有边权,如果边权的起点和终点不在同一集合(属于最小生成树和不属于最小生成树),那么连接这两个起点和终点到最小生成树里,记录最小生成树的边的答案,遍历完所有边记得到答案。

判断是不是在同一集合和链接两个点到同一个集合,我们使用并查集来做。

#include <iostream>
#include <climits>
#include <vector>
#include <algorithm>
using namespace std;

class UnionSet
{
    vector<int> father;
    int pathLength = 0;
public:
    UnionSet(int n): father(n, 0)
    {
        for (int i = 0; i < n; ++i)
            father[i] = i;
    }
    int find(int u)
    {
         return u == father[u] ? u : father[u] = find(father[u]); // 路径压缩
    }
    void Union(int u, int v)
    {
        int uRoot = find(u);
        int vRoot = find(v);
        if (uRoot == vRoot)
            return;
        father[vRoot] = uRoot;
    }
    bool isSame(int u, int v)
    {
        int uRoot = find(u);
        int vRoot = find(v);
        return uRoot == vRoot;
    }
    void addPathLength(int val)
    {
        pathLength += val;
    }
    int GetPathLength()
    {
        return pathLength;
    }
    
};
struct Edge
{
    int start, end, val;
};
int main()
{
    int V, E;
    
    cin >> V >> E;


    vector<Edge> edges;
    for (int i = 0; i < E; ++i)
    {
        int x, y, v;
        cin >> x >> y >> v;
        edges.push_back({x, y, v});
    }
    sort(edges.begin(), edges.end(), [](Edge& e1, Edge& e2){return e1.val < e2.val;});
    UnionSet unionSet(V+1);
    for (int i = 0; i < edges.size(); ++i)
    {
        int x = edges[i].start;
        int y = edges[i].end;
        int val = edges[i].val;
        if (!unionSet.isSame(x, y))
        {
            unionSet.Union(x, y);
            unionSet.addPathLength(val);
        }
    }

    cout << unionSet.GetPathLength() << endl;
}

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

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

相关文章

JSON的C实现(上)

JSON的C实现&#xff08;上&#xff09; JSON的C实现&#xff08;上&#xff09;前言JSON简介JSON的C实现思路小结 JSON的C实现&#xff08;上&#xff09; 前言 JSON是众多项目中较为常见的数据交换格式&#xff0c;为不同项目、系统间的信息交换提供了一个规范化标准。JSON…

1.7 软件缺陷管理

欢迎大家订阅【软件测试】 专栏&#xff0c;开启你的软件测试学习之旅&#xff01; 文章目录 前言1 缺陷介绍2 缺陷描述及提交3 缺陷跟踪流程4 案例分析 前言 在软件开发和测试过程中&#xff0c;缺陷&#xff08;通常称为“bug”&#xff09;是不可避免的。了解和有效管理这些…

[Unity Demo]从零开始制作空洞骑士Hollow Knight第十二集:制作完整地图和地图细节设置以及制作相机系统的跟随玩家和视角锁定功能

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、制作完整的地图和地图细节设置 1.制作地图前的设置2.制作地图前期该做的事3.制作地图之堆叠素材4.制作地图后期该做的事5.制作地图之修复意想不到的Bug二、…

ping基本使用详解

在网络中ping是一个十分强大的TCP/IP工具。它的作用主要为&#xff1a; 用来检测网络的连通情况和分析网络速度根据域名得到服务器 IP根据 ping 返回的 TTL 值来判断对方所使用的操作系统及数据包经过路由器数量。我们通常会用它来直接 ping ip 地址&#xff0c;来测试网络的连…

Cisco Secure Firewall Management Center Virtual 7.4.2 - 思科 Firepower 管理中心软件

Cisco Secure Firewall Management Center Virtual 7.4.2 - 思科 Firepower 管理中心软件 Firepower Management Center Software 请访问原文链接&#xff1a;https://sysin.org/blog/cisco-fmc-7/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 实现管理任务…

第十三届蓝桥杯真题Java 斐波那契与7(持续更新)

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;蓝桥杯关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 问题描述 斐波那契数列的递推公式为: FnFn−1Fn−2Fn​Fn−1​Fn−2​, 其中 …

喜欢把家里打扫得很干净的人,大多活成了这样,不是迷信!

生活中&#xff0c;我们常常会遇到一些喜欢把家里打扫得干干净净的人。 对于这些人来说&#xff0c;整洁的环境不仅是一种生活习惯&#xff0c;更是一种对生活的态度。 其实&#xff0c;这种生活习惯背后&#xff0c;往往隐藏着他们的命运和未来发展。 以下是喜欢把家里打扫…

c++入门 类和对象(中)

文章目录 1. 类的默认成员函数2. 构造函数3. 析构函数4. 拷贝构造函数5. 赋值运算符重载5.1 运算符重载5.2 赋值运算符重载5.3 日期类实现 6. 取地址运算符重载6.1 const成员函数6.2 取地址运算符重载 总结 1. 类的默认成员函数 默认成员函数就是用户没有显式实现&#xff0c;…

AutoGen框架进行多智能体协作—AI Agentic Design Patterns with AutoGen(一)

1. 多代理对话&#xff1a;单口喜剧 在AutoGen中&#xff0c;Agent是一个可以代表人类意图执行操作的实体&#xff0c;发送消息&#xff0c;接收消息&#xff0c;执行操作&#xff0c;生成回复&#xff0c;并与其他代理交互。AutoGen具有一个名为Conversible Agent的内置代理类…

Ps:打开与置入

在 Adobe Photoshop 中&#xff0c;理解不同的“打开”和“置入”命令及其用途&#xff0c;可以根据不同的需求选择最佳方式来管理和编辑图像文件。 ◆ ◆ ◆ 打开 1、Ps菜单&#xff1a;文件/打开 File/Open 快捷键&#xff1a;Ctrl O 用于直接打开现有的图像文件。 打开的…

httpsok-v1.17.0-SSL证书自动续签

&#x1f525;httpsok-v1.17.0-SSL证书自动续签 介绍 httpsok 是一个便捷的 HTTPS 证书自动续签工具&#xff0c;基于全新的设计理念&#xff0c;专为 Nginx 、OpenResty 服务器设计。已服务众多中小企业&#xff0c;稳定、安全、可靠。 一行命令&#xff0c;一分钟轻松搞定…

naocs注册中心,配置管理,openfeign在idea中实现模块间的调用,getway的使用

一 naocs注册中心步骤 1 nacos下载安装 解压安装包&#xff0c;直接运行bin目录下的startup.cmd 这里双击运行出现问题的情况下 &#xff08;版本低的naocs&#xff09; 在bin目录下 打开cmd 运行以下命令 startup.cmd -m standalone 访问地址&#xff1a; http://localh…

【Linux】趣味讲解“权限“的那些事(重点讲解文件权限,内含su、sudo、chmod、chown、umask等指令)

文章目录 前言1. Linux下用户的分类1.1 su 指令1.1.1 使用su指令切换到其它的用户上1.1.2 使用su指令切换到root上1.1.3 su指令的总结 1.2 sudo指令(对某条指令进行提权)1.2.1 sudo指令的语法1.2.2 由sudo指令引发的思考问题 2. 什么叫做权限2.2 文件权限2.2.1 文件类型2.2.2 文…

UART驱动学习一(UART硬件介绍)

一、UART硬件介绍 1. 串口的硬件介绍 UART的全称是Universal Asynchronous Receiver and Transmitter&#xff0c;即异步发送和接收。串口在嵌入式中用途非常的广泛&#xff0c;主要的用途有&#xff1a; 打印调试信息&#xff1b;外接各种模块&#xff1a;GPS、蓝牙&#xf…

JavaWeb 12.Tomcat10

希望明天能出太阳 或者如果没有太阳的话 希望我能变得更加阳光一点 —— 24.9.25 一、常见的JavaWeb服务器 Web服务器通常由硬件和软件共同构成 硬件&#xff1a;电脑&#xff0c;提供服务供其他客户电脑访问 软件&#xff1a;电脑上安装的服务器软件&#xff0c;安装后能提…

【鸿蒙HarmonyOS NEXT】数据存储之分布式键值数据库

【鸿蒙HarmonyOS NEXT】数据存储之分布式键值数据库 一、环境说明二、分布式键值数据库介绍三、示例代码加以说明四、小结 一、环境说明 DevEco Studio 版本&#xff1a; API版本&#xff1a;以12为主 二、分布式键值数据库介绍 KVStore简介&#xff1a; 分布式键值数据库…

手机电脑无缝对接,虫洞软件让多屏协同触手可及

在数字化时代&#xff0c;我们的日常生活和工作越来越依赖于电子设备&#xff0c;尤其是智能手机和电脑。但你是否曾因在手机和电脑之间频繁切换而感到烦恼&#xff1f;现在&#xff0c;有了虫洞软件&#xff0c;这一切都将成为过去式。 虫洞——电脑与手机的桥梁 虫洞软件&a…

Kubernetes整体架构与核心组件

一个 Kubernetes 集群的机器节点有两种角色—— Master 和 Node&#xff0c;都可由一个或多个节点组成&#xff0c;且同一个节点可以既是 Master 也是 Node。其中 Master 节点负责全局决策、资源调度、Node 与 Pod 管理&#xff0c;等等&#xff0c;属于管控节点&#xff1b;No…

【unity进阶知识4】封装unity协程工具,避免 GC(垃圾回收)

文章目录 前言封装协程工具类&#xff0c;避免 GC&#xff08;垃圾回收&#xff09;使用1.使用默认方式使用协程2.使用自定义的 CoroutineTool 工具类来等待不同的时间 完结 前言 在 Unity 中&#xff0c;使用 yield return null 、yield return new WaitForEndOfFrame()等会导…

人物型Agent开发(文心智能体平台创作分享)

开发平台&#xff1a;文心智能体平台AgentBuilder | 想象即现实 目录 一、开发灵感 &#xff08;一&#xff09;打破刻板印象 &#xff08;二&#xff09;以古鉴今&#xff0c;探索人性与情感 二、角色分析与设定 &#xff08;一&#xff09;西门庆特质 &#xff08;二&a…