图论(三)(最小生成树)

 一、图的表示(简要概述)

        对于图G=(V,E)( V 为节点的集合,E 为边的集合 = V*V 的子集)有两种表示方法:邻接链表和邻接矩阵,两种表示方法既可以表示有向图,也可以表示无向图。

        如果 G 是连通图,则 E \geq V-1,一个图连通,至少有 v -1 条边。

        邻接链表适合表示稀疏图(边的条数 E 远远小于 V^{2} ),而邻接矩阵适合表示稠密图 (E 接近 V^{2},此外要判V^{2}断两个节点之间是否有边相邻,可以快速通过邻接矩阵判断。

         1.邻接矩阵

                邻接矩阵的表示,考虑节点集合 V=\left \{ 1,2,3......n \right \} ,用一个二维数组定义邻接矩阵A\left [ 1.....n \right ]\left [ 1.....n \right ],满足以下

对于一个简单的有向图(或无向图),邻接矩阵如下:

    无向图:若 u 与 v 之间存在一条边,则 A[u][v]=A[v][u]=1 (两个方向)

    有向图:若有一条 u 指向 v 的边,则 A[u][v]=1;若有一条 v 指向 u 的边,则 A[v][u]=1(单向)

       邻接矩阵的空间消耗为O(V^{2}),无向图的邻接矩阵为对称矩阵。在某些情况下,只存储邻接矩阵的对角线及以上的部分,这样,图占用的存储空间可以减少一半。

        2.邻接链表

        Adj为一个包含 V 条链表的数组,每个节点有一个链表,对于每个节点u∈V,邻接链表Adj[u]包含所有与节点u之间有边相连的节点v。

        如果G是一个有向图,则对于边(u,v)而言,节点 v 将出现在链表 Adj [ u ]里,所有邻接链表的长度之和等于 E;如果G是一个无向图,对于边(u,v),节点v将出现在链表 Adj [ u ] 里,节点 u 将出现在链表 Adj [ v ]里,所有邻接链表的长度之和为 2*E。

        邻接链表表示法的储存空间均为 O(V+E)

二、最小生成树

        1.相关概念

        树的概念:如果一个无向连通图不包含回路(连通图中不存在环),那么就是一棵树 

        最小生成树:一个图中可能存在多条相连的边,一定可以从图中挑出一些边生成一棵树, 当每条边都存在权重时,这时候我们从图中生成一棵树(仅有n-1条边相连n个节点),生成这棵树的总代价就是每条边的权重相加之和。

        一个有 n 个点的图,边一定是 ≥ n-1,最小生成树就是在这些边中选择 n-1 条边,连接 n 个点,这 n-1 条边的边权之和是所有方案里最小的。

        2.最小生成树的应用

        要在 n 个城市之间铺设光缆,主要是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此是要使铺设光缆的总费用最低。需要找到带权的最小生成树

        3.实现最小生成树的算法

        ① prim 算法

        算法思路:

        a.选择一个起始点作为最小生成树的起点,将该起始节点加入最小生成树的集合,并标记已访问。

        b.在所有与最小生成树集合相邻的边中,选择权重最小的边和它连接的未访问节点,并将其加入最小生成树集合,并标记已访问,

        c.重复上述 b 操作,直到所有的节点都加入到最小生成树里面结束。

        算法复杂度分析: 需要考虑每个插入每个节点,并且找出当前最小生成树集合相邻边权重最小和其连接的未访问节点,因此时间复杂度为 O(n^{2})

图示:

代码运行:

// prim 算法求最小生成树 
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;
const int maxn=505;
int a[maxn][maxn];
int vis[maxn],dist[maxn];
int n,m;
int u,v,w;
long long sum=0;
int prim(int pos) 
{dist[pos]=0;    // dist[x]为当前到达节点 x 的最小权值的边(最小生成树集合中)// 一共有 n 个点,就需要 遍历 n 次,每次寻找一个权值最小的点,记录其下标for(int i=1;i<=n;i++) {int cur=0;for(int j=1;j<=n;j++)if(!vis[j] && dist[j]<dist[cur]) //找出与最小生成树集合相邻的权重最小的边cur=j; sum+=dist[cur];vis[cur]=1;for(int k=1;k<=n;k++) {// 只更新还没有找到的最小权值if(!vis[k]) dist[k]=min(dist[k],a[cur][k]);}}return sum;
}int main(void) 
{scanf("%d%d",&n,&m);memset(a,0x3f,sizeof(a));memset(dist,0x3f,sizeof(dist));for(int i=1;i<=m;i++) {scanf("%d%d%d",&u,&v,&w);a[u][v]=min(a[u][v],w);a[v][u]=min(a[v][u],w);}int value=prim(1);printf("%lld\n",sum);return 0;
} 

prim算法的优化:

        在寻找最小生成树集合相邻边的最小权重时,可以通过优先队列的方法直接进行求出,按照从小到大的顺序直接得出。

        定义一个优先队列,队列中元素记录了节点的编号和与树中顶点相连的边权,将原点压入队列中,然后弹出。执行以下操作:

        从栈顶弹出节点(按照边权排序,最短边权对应的元素弹出),判断该节点是否被访问,若没有被访问,则直接将该点加入最小生成树集合中。并且将与 u 相连的边加入队列当中。

        实现优化后的时间复杂度为 O(nlogn)

void prim(int s)
{memset(dis,0x3f,sizeof(dis));memset(vis,0,sizeof(vis));dis[s]=0;q.push((node){0,s});   // 加入优先队列while(!q.empty()){int u=q.top().v;q.pop();if(vis[u]) continue;vis[u]=1;sum+=dis[u];for(int i=0;i<map[u].size();i++){int v=map[u][i].v;int w=map[u][i].w;if(dis[v]>w){dis[v]=w;q.push((node){w,v});}}}
}

        ② Kruskal 算法

        算法思路: 按照边的权值从小到大排序,选择 n-1 条边,并且保证这 n-1 条边连接 n 个顶点

                如何保证判断某条边是多余的呢?(第 i 条边连接的两个顶点 u v在之前是连通的,该条边就不需要了)

        通过并查集的思想,如果这两个顶点有共同的“祖先”,则此条边多余。                                                                             如果这两个顶点祖先不相同,则将两个顶点合并。

       当插入的节点个数为 n 时,即已经产生了最小生成树。

 void Kruskal()
{sort(ed+1,ed+m+1,cmp);for(int i=1;i<=m;i++){int p=FindSet(ed[i].u);int q=FindSet(ed[i].v);if(p!=q){UnionSet(p,q);mst+=ed[i].bq;if(si[q]==n)return;}}
}

算法时间复杂度的分析:

        对边进行排序: O(ElgE)=O(ElogV) \, \, \, \, \, \, \, \, \, \, E\leq V^{2}

        插入操作执行次数:O(V)

        并查集 FIND-SET 次数:O(E)

        并查集 UNION 次数:O(V)

         

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

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

相关文章

【C++STL详解(四)------vector的模拟实现】

文章目录 vector各函数接口总览vector当中的成员变量介绍默认成员函数构造函数1构造函数2构造函数3拷贝构造函数赋值运算符重载函数析构函数 迭代器相关函数begin和end 容量和大小相关函数size和capacityreserveresizeempty 修改容器内容相关函数push_backpop_backinserterases…

基于open3d加载kitti数据集bin文件

前言 在自动驾驶领域&#xff0c;Kitti数据集是一个非常流行的点云数据集&#xff0c;广泛用于3D目标检测、跟踪和其他相关研究。Open3D是一个强大的开源库&#xff0c;专门用于处理和可视化三维数据。本文将介绍如何使用Open3D来加载和可视化Kitti数据集中的.bin文件。 准备…

工业路由器在工厂数字化的应用及价值

随着科技的飞速发展&#xff0c;数字化转型已成为工厂提高效率、降低成本、实现智能化管理的关键途径。在这个过程中&#xff0c;工业路由器凭借其独特的优势&#xff0c;正逐渐成为工厂数字化建设不可或缺的核心组件。本文将深入探讨工业路由器在工厂数字化中的应用及价值&…

linux与windows脚本格式必须转换,linux只有LF

如果windows下的脚本在linux下直接执行&#xff0c;则会造成无穷的错误。 在文本处理中, CR, LF, CR/LF是不同操作系统上使用的换行符. Dos和windows&#xff1a; 采用回车换行CR/LF表示下一行. UNIX/Linux &#xff1a; 采用换行符LF表示下一行. MAC OS &#xff1a; 采用回车…

《计算机网络微课堂》2-3 传输方式

本节课我们介绍几种传输方式&#xff1a; 串行传输和并行传输同步传输和异步传输单工&#xff0c;半双工‍‍以及全双工通信 ​​ ‍ 串行 我们首先来看串行传输和并行传输&#xff0c;串行传输是指‍‍数据是一个比特依次发送的&#xff0c;因此在发送端和接收端之间‍‍只…

Linux--09---RPM 、YUM

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 RPM1 什么是RPM2 RPM包的名称格式3.RPM查询命令4.RPM卸载命令5.RPM安装命令 YUM1 什么是YUMYUM优势1.自动下载RPM包并且安装2.自动处理依赖性关系&#xff0c;并且一…

【论文阅读】AID(ICCV‘23)

paper:https://arxiv.org/abs/2310.05666 code:https://github.com/YilongLv/AID Anchor-Intermediate Detector: Decoupling and Coupling Bounding Boxes for Accurate Object Detection

第十一届蓝桥杯物联网试题(国赛)

国赛题目看着简单其实还是挺复杂的&#xff0c;所以说不能掉以轻心&#xff0c;目前遇到的问日主要有以下几点&#xff1a; 本次题主要注重的是信息交互&#xff0c;与A板通信的有电脑主机和B板&#xff0c;所以处理好这里面的交互过程很重要 国赛中避免不了会收到其他选手的…

题解:P9535 [YsOI2023] 连通图计数

题意 求&#xff1a;在所有 n n n 个点 m m m 条边的无向简单连通图中&#xff0c;满足把第 i i i 个点删去后图被分为 a i a_i ai​​ 个连通块。 n − 1 ≤ m ≤ n 1 n-1\le m\le n1 n−1≤m≤n1。 思路 将 m n − 1 , m n , m n 1 mn-1,mn,mn1 mn−1,mn,mn1​ 三…

从git上拉取项目进行操作

1.Git的概念 Git是一个开源的分布式版本控制系统&#xff0c;可以有效、高速的处理从很小到非常大的项目版本管理。它实现多人协作的机制是利用clone命令将项目从远程库拉取到本地库&#xff0c;做完相应的操作后再利用push命令从本地库将项目提交至远程库。 2.Git的工作流程…

iMX6ULL 嵌入式linux开发 | 4G无线广播终端实现方案介绍

现有的有线广播&#xff0c;如村上的大喇叭&#xff0c;需要布线&#xff0c;施工麻烦。借助现有的4G网络&#xff0c;传输音频流完全没问题&#xff0c;4G网络结合流媒体技术和MQTT消息传递实现设备间的同步推拉流。这种方案可以避免有线布线的麻烦&#xff0c;同时实现4G无线…

Mysql插入中文内容报错解决及其Mysql常用的存储引擎说明

一、问题描述 我们在Mysql数据库的表中插入带有中文内容时报错,提示【1366 - Incorrect string value: \xE5\x8C\x97\xE4\xBA\xAC... for column UserDealer at row 1】,如下图所示: 二、问题分析 一般来说插入中文内容有问题我们首先想到的就是编码问题;我们可以查看该表使…

【Python】 如何在Python中导入其他Python文件?

基本原理 在Python编程中&#xff0c;我们经常需要将代码组织成模块&#xff0c;以便于重用和维护。模块是包含Python定义和语句的文件。导入模块可以让你访问其他文件中定义的函数、类和变量等。Python提供了几种不同的方法来导入模块。 代码示例 示例1&#xff1a;导入整个…

超值分享50个DFM模型格式的素人直播资源,适用于DeepFaceLive的DFM合集

50直播模型&#xff1a;点击下载 作为直播达人&#xff0c;我在网上购买了大量直播用的模型资源&#xff0c;包含男模女模、明星脸、大众脸、网红脸及各种稀缺的路人素人模型。现在&#xff0c;我将这些宝贵的资源整理成合集分享给大家&#xff0c;需要的朋友们可以直接点击下…

在线生成数据库er图的工具

网址 https://databasediagram.com/ 其实很早之前我也有类似的想法&#xff0c;根据数据表结构&#xff0c;显示数据表之间的关系图。 当时我还写了一个工具&#xff0c;可惜后来就没怎么用过了。 这个网站和我当时的思路很像&#xff0c;只不过他这个页面显示比我的好得多&…

苍穹外卖--sky-take-out(一)

目录 d1 软件开发流程 项目介绍 产品原型 技术选型 前端环境搭建 后端环境搭建 Git版本控制 数据库环境搭建 nginx反向代理和负载均衡 导入接口文档 Swagger 问题 d2 用户登录 代码实现 MD5密码加密 新增员工 需求分析与设计 代码开发 代码完善&#xff08;Threa…

ACW石子合并-XMUOJ元素共鸣:唤醒神之眼 -区间DP

题目 思路 话不多说&#xff0c;直接上代码 代码 /* ACW石子合并-XMUOJ元素共鸣&#xff1a;唤醒神之眼 JinlongW-2024/05/25 区间DP 当i<j时&#xff0c;f[i][j]min(f[i][k]f[k][j]s[j]-s[i-1]) 当ij时&#xff0c;f[i][j]0 最终答案&#xff1a;f[1][n] *//* 区间DP…

maven-依赖管理

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Maven BOM二、使用三、SpringBoot的依赖管理 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 依赖管理能带来啥&#xff1a; 避免…

linux文件权限常用知识点,基于Linux(openEuler、CentOS8)

目录 知识点常用实例 知识点 真实环境文件显示 解读 常用实例 文件所有者 chown -R nginx:nginx /home/source目录权限(R选填必须大写<遍历子文件夹及文件>) chmod -R 755 /home/sourcechmod -R 777 /home/source

如何使用甘特图来做任务管理?zz-plan甘特图的实践指南

在项目管理和任务调度中&#xff0c;甘特图是一种非常实用的工具&#xff0c;它可以帮助团队成员清晰地规划、执行和跟踪项目进度。然而&#xff0c;如何有效利用甘特图进行任务管理&#xff0c;对于许多团队来说仍然是一个挑战。本文将结合 zz-plan https://zz-plan.com/ 甘特…