【图的应用一:最小生成树】- 用 C 语言实现普里姆算法

目录

一、最小生成树 

二、普里姆算法的构造过程

三、普里姆算法的实现


 


一、最小生成树 

假设要在 n 个城市之间建立通信联络网,则连通 n 个城市只需要 n - 1 条线路。这时,自然会考虑这样一个问题,如何在最节省经费的前提下建立这个通信网。

在每两个城市之间都可设置一条线路,相应地都要付出一定的经济代价。n 个城市之间,最多可能设置 ​ C_n^2 = \dfrac{n(n - 1)}{2} 条线路,那么如何在这些可能的线路中选择 n - 1 条,以使总的耗费最少呢

可以用连通网来表示 n 个城市,以及 n 个城市间可能设置的通信路线,其中网的顶点表示城市,边表示两城市之间的线路,赋予边的权值表示相应的代价。对于 n 个顶点的连通网可以建立许多不同的生成树,每一颗生成树都可以是一个通信网,最合理的通信网应该是各边代价之和最小的那颗生成树,称为连通网的最小代价生成树(Minimum Cost Spanning Tree),简称最小生成树

构造最小生成树有多种算法,其中多数算法利用了最小生成树的下列一种简称为 MST 的性质

假设 N = (V, E) 是一个连通网,U 是顶点集 V 的一个非空真子集。若 (u, v) 是 N 中所有的一个顶点在 U(u \in U​)中,另一个顶点在 V - U(​v \in V - U)中的边里,具有最小权值的一条边,则必存在一棵包含边 (u, v) 的最小生成树。

可以用反证法来证明

假设网 N 的任何一棵最小生成树都不包含边 (u, v),T 是连通网上的一棵最小生成树,由生成树的定义可知,T 中必存在一条从 u 到 v 的路径 P,且在 P 上必存在一条边 (u', v'),其中 u' \in U, v' \in V - U​。

当将边 (u, v) 加入到 T 中时,(u, v) 和 P 构成了一条回路,删去 (u', v') 便可消除回路,同时得到另一颗生成树 T‘。因为 (u, v) 的权值不高于 (u', v'),所以 T' 的权值亦不高于 T,那么 T’ 是包含 (u, v) 的一棵最小生成树,和假设矛盾。

普里姆(Prim)算法克鲁斯卡尔(Kruskal)算法是两个利用 MST 性质构造最小生成树的算法。


二、普里姆算法的构造过程

假设 N = (V, E) 是连通网,TE 是 N 上最小生成树中边的集合。

  1. U = \{u_0\}(u_0 \in V), TE = \{\}​。

  2. 在所有 ​u \in U, v \in V - U 的边 (u, v) \in E 中找一条权值最小的边 (u_0, v_0) 并入集合 TE,同时 ​v_0 并入 U。

  3. 重复 2,直至 U = V 为止。

此时 TE 中必有 n - 1 条边,则 T = (V, TE) 为 N 的最小生成树。

下图所示为一个连通网 G5 从 v1 开始构造最小生成树的例子。可以看出,普里姆算法逐步增加 U 中的顶点,可称为 "加点法"

每次选择最小边时,可能存在多条同样权值的边可选,此时任选其一即可


三、普里姆算法的实现

假设无向网 N邻接矩阵形式存储,从顶点 u 出发构造 N 的最小生成树 T,要求输出 T 的各条边。

为实现这个算法附设了两个辅助数组 lowcostArr 和 adjVexPosArr。对每个顶点 ,lowcostArr[i - 1] = Min{ cost​ },即表示 N 中所有的一个顶点在 U 中,另一个顶点是 vi 的边里,最小边上的权值;adjVexPosArr[i - 1] 则表示那条最小边在 U 中的那个顶点在图中的位置

AMGraph.h

#pragma once
​
// 无向网
typedef char VertexType;
typedef int EdgeType;
​
#define DEFAULT_CAPACITY 2
​
typedef struct AMGraph
{VertexType* vertices;EdgeType** edges;int vSize;int eSize;int capacity;
}AMGraph;
​
// 基本操作
void AMGraphInit(AMGraph* pg);
​
void ShowAdjMatrix(AMGraph* pg);
​
int GetVertexPos(AMGraph* pg, VertexType v);
​
void InsertVertex(AMGraph* pg, VertexType v);
void InsertEdge(AMGraph* pg, VertexType v1, VertexType v2, EdgeType cost);
​
// 普里姆算法
void MiniSpanTree_Prim(AMGraph* pg, VertexType u);

AMGraph.c

#include "AMGraph.h"
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
​
void AMGraphInit(AMGraph* pg)
{assert(pg);pg->vSize = pg->eSize = 0;pg->capacity = DEFAULT_CAPACITY;pg->vertices = (VertexType*)malloc(sizeof(VertexType) * pg->capacity);assert(pg->vertices);
​pg->edges = (EdgeType**)malloc(sizeof(EdgeType*) * pg->capacity);assert(pg->edges);for (int i = 0; i < pg->capacity; ++i){pg->edges[i] = (EdgeType*)malloc(sizeof(EdgeType) * pg->capacity);assert(pg->edges[i]);for (int j = 0; j < pg->capacity; ++j){if (i == j)pg->edges[i][j] = 0;elsepg->edges[i][j] = INT_MAX;}}
}
​
void ShowAdjMatrix(AMGraph* pg)
{assert(pg);printf("  ");for (int i = 0; i < pg->vSize; ++i){printf("%c ", pg->vertices[i]);}printf("\n");
​for (int i = 0; i < pg->vSize; ++i){printf("%c ", pg->vertices[i]);for (int j = 0; j < pg->vSize; ++j){if (pg->edges[i][j] == INT_MAX)printf("# ");  // 用 # 代替 ∞elseprintf("%d ", pg->edges[i][j]);}printf("\n");}
}
​
int GetVertexPos(AMGraph* pg, VertexType v)
{assert(pg);for (int i = 0; i < pg->vSize; ++i){if (pg->vertices[i] == v)return i;}return -1;
}
​
void InsertVertex(AMGraph* pg, VertexType v)
{assert(pg);// 考虑是否需要扩容if (pg->vSize == pg->capacity){VertexType* tmp1 = (VertexType*)realloc(pg->vertices, sizeof(VertexType) * 2 * pg->capacity);assert(tmp1);pg->vertices = tmp1;
​EdgeType** tmp2 = (EdgeType**)realloc(pg->edges, sizeof(EdgeType*) * 2 * pg->capacity);assert(tmp2);pg->edges = tmp2;for (int i = 0; i < pg->capacity; ++i){EdgeType* tmp3 = (EdgeType*)realloc(pg->edges[i], sizeof(EdgeType) * 2 * pg->capacity);assert(tmp3);pg->edges[i] = tmp3;for (int j = pg->capacity; j < 2 * pg->capacity; ++j){pg->edges[i][j] = INT_MAX;  }}for (int i = pg->capacity; i < 2 * pg->capacity; ++i){pg->edges[i] = (EdgeType*)malloc(sizeof(EdgeType) * 2 * pg->capacity);assert(pg->edges[i]);for (int j = 0; j < 2 * pg->capacity; ++j){if (i == j)pg->edges[i][j] = 0;elsepg->edges[i][j] = INT_MAX;}}
​pg->capacity *= 2;}// 插入顶点pg->vertices[pg->vSize++] = v;
}
​
void InsertEdge(AMGraph* pg, VertexType v1, VertexType v2, EdgeType cost)
{assert(pg);int pos1 = GetVertexPos(pg, v1);int pos2 = GetVertexPos(pg, v2);if (pos1 == -1 || pos2 == -1)return;
​if (pg->edges[pos1][pos2] != INT_MAX)return;
​pg->edges[pos1][pos2] = pg->edges[pos2][pos1] = cost;++pg->eSize;
}
​
// 普里姆算法的实现
void MiniSpanTree_Prim(AMGraph* pg, VertexType u)
{assert(pg);EdgeType* lowcostArr = (EdgeType*)malloc(sizeof(EdgeType) * pg->vSize);int* adjVexPosArr = (int*)malloc(sizeof(int) * pg->vSize);assert(lowcostArr && adjVexPosArr);
​int pos = GetVertexPos(pg, u);if (pos == -1)return;for (int i = 0; i < pg->vSize; ++i){if (i != pos){lowcostArr[i] = pg->edges[pos][i];adjVexPosArr[i] = pos;}else{lowcostArr[i] = 0;  // 初始,U = {u}}}// 选择其余 pg->vSize - 1 个顶点,生成 pg->vSize - 1 条边for (int i = 0; i < pg->vSize - 1; ++i){EdgeType min = INT_MAX;int minIndex = -1;for (int j = 0; j < pg->vSize; ++j){if (lowcostArr[j] != 0 && lowcostArr[j] < min){min = lowcostArr[j];minIndex = j;}}printf("(%c, %c)\n", pg->vertices[adjVexPosArr[minIndex]], pg->vertices[minIndex]);lowcostArr[minIndex] = 0;  // 将顶点并入 U 
​for (int j = 0; j < pg->vSize; ++j){if (pg->edges[minIndex][j] < lowcostArr[j]){lowcostArr[j] = pg->edges[minIndex][j];adjVexPosArr[j] = minIndex;}}}free(lowcostArr);free(adjVexPosArr);
}

Test.c

#include "AMGraph.h"
#include <stdio.h>
​
int main()
{AMGraph g;AMGraphInit(&g);InsertVertex(&g, 'A');InsertVertex(&g, 'B');InsertVertex(&g, 'C');InsertVertex(&g, 'D');InsertVertex(&g, 'E');InsertVertex(&g, 'F');InsertEdge(&g, 'A', 'B', 6);InsertEdge(&g, 'A', 'C', 1);InsertEdge(&g, 'A', 'D', 5);InsertEdge(&g, 'B', 'C', 5);InsertEdge(&g, 'B', 'E', 3);InsertEdge(&g, 'C', 'D', 5);InsertEdge(&g, 'C', 'E', 6);InsertEdge(&g, 'C', 'F', 4);InsertEdge(&g, 'D', 'F', 2);InsertEdge(&g, 'E', 'F', 6);ShowAdjMatrix(&g);printf("\n");
​MiniSpanTree_Prim(&g, 'A');return 0;
}

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

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

相关文章

机器学习之无监督学习

聚类&#xff1a;发掘纵向结构的某种模式信息&#xff0c;某些x属于相同的分布或者类别 特征学习&#xff1a;发掘横向结构的某种模式信息&#xff0c;每一行都可以看成是一种属性或特征 密度估计&#xff1a;发掘底层数据分布&#xff0c;x都是从某个未知分布p(x)采出来的&a…

(四)STM32 操作 GPIO 点亮 LED灯 / GPIO工作模式

目录 1. STM32 工程模板中的工程目录介绍 2. GPIO 简介 3. GPIO 框图剖析 1&#xff09;保护二极管及上、下拉电阻 2&#xff09; P-MOS 管和 N-MOS 管 3&#xff09;输出数据寄存器 3.1&#xff09;ODR 端口输出数据寄存器 3.2&#xff09;BSRR 端口位设置/清除寄存器 4&a…

【Java代码审计】目录穿越篇

【Java代码审计】目录穿越篇 1.Java中的目录穿越2.目录穿越漏洞审计3.Java中目录穿越漏洞修复 1.Java中的目录穿越 目录穿越漏洞产生的本质是路径可控&#xff0c;一旦涉及文件的读取问题便会涉及java.io.File类&#xff0c;因此在审计这类漏洞时可以优先查找java.io.File引用…

最强Pose模型RTMO开源 | 基于YOLO架构再设计,9MB+9ms性能完爆YOLO-Pose

实时多人在图像中的姿态估计面临着在速度和精度之间实现平衡的重大挑战。尽管两阶段的上下文方法在图像中人数增加时会减慢速度&#xff0c;但现有的单阶段方法往往无法同时实现高精度和实时性能。 本文介绍了RTMO&#xff0c;这是一个单阶段姿态估计框架&#xff0c;通过在YOL…

超文本传送协议HTTP

目录 HTTP简介&#xff1a; URL的格式&#xff1a; HTTP协议的特点&#xff1a; HTTP/1.0协议&#xff1a; HTTP/1.1协议&#xff1a; HTTP/2: HTTP代理服务器&#xff1a; HTTP的报文结构&#xff1a; 请求报文的特点&#xff1a; 响应报文的特点&#xff1a; Cook…

小 cookie,大作用:探索网站中的隐私追踪器(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

大华 DSS 数字监控系统 itcBulletin SQL 注入漏洞复现

0x01 产品简介 大华 DSS 数字监控系统是大华开发的一款安防视频监控系统,拥有实时监视、云台操作、录像回放、报警处理、设备管理等功能。 0x02 漏洞概述 大华 DSS存在SQL注入漏洞,攻击者 /portal/services/itcBulletin 路由发送特殊构造的数据包,利用报错注入获取数据库…

springboot——定时任务、异步任务

springboot——定时任务、异步任务 一、定时任务1、创建一个定时任务、时间配置文件2、springboot主程序开启定时任务 EnableScheduling3、使用 Scheduled 注解 二、定时任务、异步执行。1、springboot主程序开启异步任务 EnableAsync2、方法上增加 Async 注解&#xff0c;标识…

【JAVA日志框架】JUL,JDK原生日志框架详解。

前言 Java日志体系混乱&#xff1f;Java日志框架系列&#xff0c;清晰简洁整理好整个Java的日志框架体系。第一篇&#xff0c;JDK原生日志框架——JUL。 目录 1.概述 2.日志级别 3.配置 4.继承关系 1.概述 日志框架的核心问题&#xff1a; 日志是用来记录应用的一些运行…

nodejs+vue+微信小程序+python+PHP校园二手交易系统的设计与实现-计算机毕业设计推荐

(2)管理员 进行维护&#xff0c;以及平台的后台管理工作都依靠管理员&#xff0c;其可以对信息进行管理。需具备功能有&#xff1b;首页、个人中心、学生管理、物品分类管理、物品信息管理、心愿贴、系统管理、订单管理等功能。系统分成管理员控制模块和学生模块。 本系统有良好…

maven+spock

pom配置 话说JunitMockito的组合用起来是真难用&#xff0c;还是Spock的简单&#xff0c;尤其是参数化的测试。junit的Parameter是鸡肋&#xff0c;杂恶心&#xff1b;Theories用来也不爽。 <?xml version"1.0" encoding"UTF-8"?><project xm…

Spring容器中scope为prototype类型Bean的回收机制

文章目录 一、背景二、AutowireCapableBeanFactory 方法 autowireBean 分析三、Spring 容器中 scope 为 prototype 类型 Bean 的回收机制四、总结 一、背景 最近做 DDD 实践时&#xff0c;遇到业务对象需要交给 Spring 管理才能做一些职责内事情。假设账号注册邮箱应用层代码流…

Flask学习三:模型操作

ORM flask 通过Model操作数据库&#xff0c;不管你的数据库是MySQL还是Sqlite&#xff0c;flask自动帮你生成相应数据库类型的sql语句&#xff0c;所以不需要关注sql语句和类型&#xff0c;对数据的操作flask帮我们自动完成&#xff0c;只需要会写Model就可以了 flask使用对象关…

第十五章总结

一.输入/输出流 1.输入流 InputStrema类是字节输入流的抽象类&#xff0c;它是所有字节输入流的父类。 该类中所有方法遇到错误都会引发IOException异常。 read()方法&#xff1a;从输入流中读取数据的下一个字节。返回0~255的int字节值。如果因为已经到达流末尾而没有可用的…

【模块化】 js 模块化(CommonJS, AMD, UMD, CMD, ES6)

目录 js 的演变模块化1. CommonJS 规范commonJs伪代码⭐CommonJS优缺点 2. AMD 规范⭐AMD 优缺点 3. UMD 规范⭐UMD AMD CommonJS 4. CMD 规范⭐CMD 优缺点 5. ES6 模块化符号绑定⭐ESM 优缺点 AMD 和 CMD 的区别ES6 模块与 CommonJS 模块的差异参考 将介绍几种 js 模块化的规…

新能源汽车的“一池春水”,或许不再由价格战掀起波澜?

2005年12月15日&#xff0c;丰田普锐斯混合动力车进入中国&#xff0c;拉开了国内新能源汽车发展的序幕。18年后的今天&#xff0c;国产及进口的新能源汽车已经渗透我国超三分之一的乘用车市场&#xff0c;与油车二分天下的愿景渐趋实现。 今年11月&#xff0c;随着购车需求进…

轻量封装WebGPU渲染系统示例<50>- Json数据描述材质等场景信息

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/feature/material/src/voxgpu/sample/DataDrivenScene2.ts 当前示例运行效果: 此示例基于此渲染系统实现&#xff0c;当前示例TypeScript源码如下: json场景数据: {"renderer": {"mtplE…

105基于matlab的阶次分析算法

基于matlab的阶次分析算法&#xff0c;用于变转速机械故障特征提取&#xff0c;可运行&#xff0c;包含寻找脉冲时刻&#xff0c;等角度时刻。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 105阶次分析变转速信号处理 (xiaohongshu.com)

云原生之深入解析亿级流量架构之服务限流思路与方法

一、限流思路 ① 熔断 系统在设计之初就把熔断措施考虑进去&#xff0c;当系统出现问题时&#xff0c;如果短时间内无法修复&#xff0c;系统要自动做出判断&#xff0c;开启熔断开关&#xff0c;拒绝流量访问&#xff0c;避免大流量对后端的过载请求。系统也应该能够动态监测…

【Vulnhub 靶场】【VulnCMS: 1】【简单】【20210613】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/vulncms-1,710/ 靶场下载&#xff1a;https://download.vulnhub.com/vulncms/VulnCMS.ova 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年06月13日 文件大小&#xff1a;1.4 GB 靶场作者&#xff1a;to…