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

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

        对于图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…

掌握安全渗透测试:利用永恒之黑漏洞获取Windows 10系统访问权限

以下是利用永恒之黑漏洞对Windows 10进行渗透测试的步骤&#xff1a; 环境介绍 靶机&#xff1a;IP地址为192.168.1.60&#xff0c;运行Windows 10 1903版本。攻击机&#xff1a;IP地址为192.168.1.53。 靶机准备 检查Windows 10版本号&#xff1a;确保靶机运行的Windows 1…

鼠标滚轮使用时上下跳动的解决方法

前阵子鼠标滚轮使用时总会出现上下跳动比如向下滚动会往上反弹或者是在当前框架卡住但颤动的情况&#xff0c;这个问题困扰了我很久&#xff0c;试过了很多设置和驱动方面的办法都没解决&#xff0c;因此大概率是滚轮那有脏东西了。最后终于在一个答复下面看到了一种不用拆开修…

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

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

类脑计算和量子计算、人工智能的关系

According to www.iAsk.ai Ask Ai Search Engine: 类脑计算、量子计算和人工智能是三个不同但相关的领域。它们在不同层面上探索和利用了不同的计算模型和技术&#xff0c;但都旨在推动计算能力的发展和创新。 类脑计算是一种受到人脑神经系统启发的计算模型。它试图通过模拟…

页面置换算法

一、实验目的&#xff1a; 通过编写一个页面置换算法的模拟程序&#xff0c;深入理解并比较最佳置换算法、先进先出算法和最近最久未使用算法在操作系统中的应用和性能差异。同时&#xff0c;通过实验&#xff0c;加深对操作系统中内存管理相关概念的理解。 实验设备与实验环境…

并查集Java实现以及leetcode例题

Java 模板 public class UnionFindSet {// 节点数private int N 1005;// 每个节点的父节点private int[] father new int[N];/*** 并查集初始化*/public void init() {for (int i 0; i < N; i) father[i] i;}/*** 查询节点的父节点下标&#xff08;路径压缩&#xff09…

时政|杂粮产业

政策支持 《新一轮千亿斤粮食产能提升行动方案&#xff08;2024—2030年&#xff09;》明确&#xff0c;按照“巩固提升口粮、主攻玉米大豆、兼顾薯类杂粮”的思路&#xff0c;因地制宜发展马铃薯、杂粮杂豆等品种&#xff0c;根据市场需求优产稳供。 产地发展 河北省石家庄…

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

随着科技的飞速发展&#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; 采用回车…

作业39 sqrt应用

目录 判断完全平方数 题目描述 输出所有因数 题目描述 因子求和 题目描述 判断素数 题目描述 判断完全平方数 题目描述 输入一个整数&#xff0c;判断他是否是完全平方数&#xff0c;如果是&#xff0c;输出yes&#xff0c;否则输出no 样例 样例…

《计算机网络微课堂》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的工作流程…

C# 实现腾讯云 IM 常用 REST API 之会话管理

目录 关于腾讯 IM REST API 开发前准备 范例运行环境 常用会话管理API 查询账号会话总未读数 查询单聊会话消息记录 下载最近会话记录 小结 关于腾讯 IM REST API REST API 是腾讯即时通信 IM 提供给服务端的一组 HTTP 后台管理接口&#xff0c;如消息管理、群组管理…

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

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

[力扣题解] 344. 反转字符串

题目&#xff1a;344. 反转字符串 思路 双指针法 代码 class Solution { public:void reverseString(vector<char>& s) {int i, j, temp;for(i 0, j s.size()-1; i < j; i, j--){temp s[j];s[j] s[i];s[i] temp;}} };