当前位置: 首页 > news >正文

图的应用1.0-----最小生成树问题

 目录

前言

生成树

1.基本概念

 2.生成树的特点

 3.生成树形成过程

最小生成树(Minimum Spanning Tree)

1.基本概念

2.构造方法(MST)

普里姆(Prime)算法

1.算法思想

2.代码实现

克鲁斯卡尔(Kruskal)算法

1.算法思想

 2.代码实现

Prime算法与Kruskal算法比较


前言

        今天我们学习图的应用,对于最小生成树问题,那什么是最小生成树呢?图又这么去实现一个生成树和最小生成树?下面我们就一起来看看。

生成树

1.基本概念

生成树:所有顶点均由边连接在一起,但不存在回路的图。

 如上图所示,除了第一个不是生成树(因为存在环),其他都是生成树。

 2.生成树的特点

图的生成树有以下特点:

  • 一个图可以有许多棵不同的生成树
  • 生成树的顶点个数与图的顶点个数相同
  • 生成树是图的极小连通子图,去掉一条边则非连通
  • 一个有n个顶点的连通图的生成树有n-1条边
  • 在生成树中再加一条边必然形成回路。
  • 生成树中任意两个顶点间的路径是唯一的

 3.生成树形成过程

形成过程:

设图G=(V,E)是个连通图,当从图任一顶点出发遍历图G时,将边集E(G)分成两个集合T(G)和B(G)。其中T(G)是遍历图时所经过的边的集合,B(G)是遍历图时未经过的边的集合。显然,G1(V,T)是图G的极小连通子图。即子图G1是连通图G的生成树。

最小生成树(Minimum Spanning Tree)

1.基本概念

最小生成树:给定一个无向网络,在该网的所有生成树中,使得各边权值之和最小的那棵生成树称为该网的最小生成树,也叫最小代价生成树。

如图所示,连通图的最小生成树权值之和为17才是最小生成树

2.构造方法(MST)

最小生成树(Minimum Spanning Tree),根据其英文名字有一个叫MST算法用于去构造最小生成树,MST算法本质是一种贪心算法,根据贪心算法的方式去获取到最优解。

 MST 性质:设N= (V,E)是一个连通网,U是顶点集V的一个非空子集。若边(u, v)是一条具有最小权值的边,其中uEu,vEV-U,则必存在一棵包含边(u, v)的最小生成树。

MST解释说明:

在生成树的构造过程中,图中n个顶点分属两个集合: 

  • 已落在生成树上的顶点集:u ·已落在生成树上的顶点集:U
  • 尚未落在生成树上的顶点集:V-U ·尚未落在生成树上的顶点集:V-U

接下来则应在所有连通U中顶点和V-U中顶点的边中选取权值最小的边 接下来则应在所有连通U中顶点和V-U中顶点的边中选取权值最小的边

下面我就介绍两种MST算法,分别是Prim算法和Kruskal算法。

以下代码是一个图的邻接矩阵创建代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define Maxint 32767
#define Maxnum 100//最大顶点数//数据类型
typedef struct d {char id[10];//……
}
ElemType;
//图的邻接数组
typedef struct graph {ElemType vexs[Maxnum];//图数据int matrix[Maxnum][Maxnum];//二维数组int vexnum;//点数int arcnum;//边数
}Graph;//节点id查找下标
int Locate_vex(Graph G, char* id) {for (int i = 0; i < G.vexnum; i++)if (strcmp(G.vexs[i].id, id) == 0)return i;return -1;
}//构造邻接矩阵(无向图,对称矩阵)(有向图)赋权图
void Create_graph(Graph* G) {printf("请输入顶点个数和边的个数:\n");scanf("%d %d", &G->vexnum, &G->arcnum);//输入点数边数printf("请输入顶点数据:\n");for (int i = 0; i < G->vexnum; i++) {scanf("%s", G->vexs[i].id);}for (int x = 0; x < G->vexnum; x++) {for (int y = 0; y < G->vexnum; y++) {if (x == y)G->matrix[x][y] = 0;//对角线初始化为0elseG->matrix[x][y] = Maxint;//其他初始化为Maxint}}printf("请输入边相关数据:\n");for (int k = 0; k < G->arcnum; k++) {char a[10], b[10];int w;scanf("%s %s %d", a, b, &w);//a->bint i = Locate_vex(*G, a);int j = Locate_vex(*G, b);//矩阵赋值G->matrix[i][j] = w;G->matrix[j][i] = w;//删掉这个,表示有向图}
}//输出矩阵
void print_matrix(Graph G) {printf("矩阵为:\n");for (int i = 0; i < G.vexnum; i++) {for (int j = 0; j < G.vexnum; j++) {if(G.matrix[i][j]==Maxint)printf("∞\t");elseprintf("%d\t", G.matrix[i][j]);}printf("\n");}printf("图的顶点个数和边数:%d,%d\n", G.vexnum, G.arcnum);
}//遍历
void visit(Graph G, int loca) {printf("%s ", G.vexs[loca].id);
}

普里姆(Prime)算法

1.算法思想

Prime算法的核心步骤是:在带权连通图中V是包含所有顶点的集合, U已经在最小生成树中的节点,从图中任意某一顶点v开始,此时集合U={v},重复执行下述操作:在所有u∈U,w∈V-U的边(u,w)∈E中找到一条权值最小的边,将(u,w)这条边加入到已找到边的集合,并且将点w加入到集合U中,当U=V时,就找到了这颗最小生成树

        其实,算法的核心步骤就是:在所有u∈U,w∈V-U的边(u,w)∈E中找到一条权值最小的边。

过程如下图所示:

2.代码实现

							//最小生成树
//生成树
typedef struct shortedge {char adjvex_id[10];//储存到的数据idint lowcost;//到其他顶点最短路径距离
}ShortEdge;
//01---Prim算法							
//在U集合中找到距离其他顶点最近的下一个顶点位置
int min_path(Graph G, ShortEdge* shortedge) {int  location;int min = Maxint;for (int i = 1; i < G.vexnum; i++) {if (min > shortedge[i].lowcost && shortedge[i].lowcost != 0) {min = shortedge[i].lowcost;location = i;}}return location;
}
//Prim接口
void MST_Prim(Graph G, char* start) {printf("(Prim)最小生成树如下:\n");ShortEdge shortdege[Maxnum];//集合Uint sum = 0;//统计最短路径权之和//对第一个起始数据start初始化处理,把第一个顶点放入到集合U当中int k = Locate_vex(G, start);//当前集合U只有顶点start,那么里面的数据就储存start的数据for (int i = 0; i < G.vexnum; i++) {strcpy(shortdege[i].adjvex_id, start);shortdege[i].lowcost = G.matrix[k][i];}shortdege[k].lowcost = 0;//此顶点对应的下标标记为0,表示已经加入集合U当中//后继处理for (int i = 0; i < G.vexnum-1; i++) {//找到下一个离集合U最近的顶点,下标为kk = min_path(G, shortdege);sum += shortdege[k].lowcost;printf("%s->%s %d\n", shortdege[k].adjvex_id, G.vexs[k].id, shortdege[k].lowcost);shortdege[k].lowcost = 0;//此顶点对应的下标标记为0,表示已经加入集合U当中//加入了新的顶点后,对集合U到其他顶点最近距离的值进行更新for (int j = 0; j < G.vexnum; j++) {if (G.matrix[k][j] < shortdege[j].lowcost && shortdege[j].lowcost!=0) {shortdege[j].lowcost = G.matrix[k][j];strcpy(shortdege[j].adjvex_id, G.vexs[k].id);}}}printf("最小生成树权之和为:%d\n", sum);
}

 测试结果:

int main() {Graph G;Create_graph(&G);print_matrix(G);MST_Prim(G, "V1");
}

克鲁斯卡尔(Kruskal)算法

1.算法思想

克鲁斯卡尔算法是一种用于求解最小生成树问题的贪心算法。 最小生成树是一个连通图的生成树,其边的权重之和最小。 一、原理 克鲁斯卡尔算法的核心思想是按照边的权重从小到大逐渐选择连通图的边,直到所有顶点都被连接为止。 在每一步中,选择当前权重最小的边,若该边的两个顶点尚未连接,则将其添加到最小生成树的边集合中,并将这两个顶点归为同一个连通分量。克鲁斯卡尔(Kruskal)算法又称作为避圈法。

过程如下:

 2.代码实现

这里就需要对边进行权值的大小排序,直接就用快速排序去进行排序,(头文件.h)如下:

#pragma once
//边的结构体数据
typedef struct edge {char begin_id[10];//边起点的idchar end_id[10];//边终点的idint weight;//权值
}Edge;
void quick_sort(Edge* n, int left, int right);

快速排序源文件.c代码如下:

#include"sort.h"
//快速排序---递归实现
void quick_sort(Edge* n, int left, int right) {int i, j, temp;i = left;j = right;if (i > j) {return;}else {temp = n[left].weight;while (i != j) {while (n[j].weight >= temp && i < j)//先向左移动jj--;while (n[i].weight <= temp && i < j) //再向右移动ii++;if (i < j) {//此时对i和j指向的数字进行数字交换Edge num = n[i];n[i] = n[j];n[j] = num;}}//当i和j相遇的时候就结束循环//此时i与j相遇,就与temp交换Edge new_temp = n[i];n[i] = n[left];n[left] = new_temp;}//最后左右边依次进入到递归quick_sort(n, left, i - 1); //左边的数字都比temp要小quick_sort(n, i + 1, right);  //右边的数字都比temp要大
}

克鲁斯卡尔(Kruskal)算法代码如下:

						//最小生成树//02--Kruskal算法
//对边排序
Edge* arc_sort(Graph G) {//创建边数据Edge* edge = (int*)malloc(sizeof(Edge) * G.arcnum);int count = 0;//把边的数据储存到edge里面(无向图)for (int i = 0; i < G.vexnum; i++) {for (int j = 0; j <= i; j++) {if (G.matrix[i][j] != Maxint && G.matrix[i][j] != 0) {strcpy(edge[count].begin_id, G.vexs[i].id);strcpy(edge[count].end_id, G.vexs[j].id);edge[count].weight = G.matrix[i][j];count++;}}}//对边的权值进行排序quick_sort(edge, 0, count - 1);return edge;
}//接口
void MST_Kruskal(Graph G) {Edge* edge = arc_sort(G);int sum = 0;int vset[Maxnum];//辅助数组判断连通性//初始化为01234……表示开始的时候都不连通for (int i = 0; i < G.vexnum; i++)vset[i] = i;for (int i = 0; i < G.arcnum; i++) {int a = Locate_vex(G, edge[i].begin_id);//a为起点顶点的位置下标int b = Locate_vex(G, edge[i].end_id);//b为这个边终点的位置下标int v1 = vset[a];//辅助数组中找到起点的连通标准int v2 = vset[b];//辅助数组中找到终点的连通标准//判断v1与v2是否相等,判定是否成环if (v1!=v2) {printf("%s——%s %d\n", edge[i].begin_id, edge[i].end_id, edge[i].weight);sum += edge[i].weight;for (int j = 0; j < G.vexnum; j++) {//与v1连通的数据全部改成v2,表示整体连通if (vset[j] == v1)vset[j] = v2;}}}printf("最小生成树的权值之和:%d\n", sum);//释放空间free(edge);edge = NULL;
}

测试结果: 

int main() {Graph G;Create_graph(&G);print_matrix(G);MST_Kruskal(G);
}

Prime算法与Kruskal算法比较

 

以上就是本期的全部内容了,我们下一次见!

分享一张壁纸:

相关文章:

图的应用1.0-----最小生成树问题

目录 前言 生成树 1.基本概念 2.生成树的特点 3.生成树形成过程 最小生成树(Minimum Spanning Tree) 1.基本概念 2.构造方法&#xff08;MST&#xff09; 普里姆(Prime)算法 1.算法思想 2.代码实现 克鲁斯卡尔&#xff08;Kruskal&#xff09;算法 1.算法思想 2.代码…...

【计算机网络笔记】网络应用对传输服务的需求

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…...

IDEA启动报错:Command line is too long的解决办法

文章目录 1.报错现象2.解决办法验证3.最佳实践4.问题原因5.参考文献1.报错现象 在idea中启动一个spring cloud项目时,编译完成后直接报错,报错内容如下: Error running XXXApplication:Command line is too long. Shorten command line for XXXApplication or also for Sp…...

Android 中的 本地广播LocalBroadcastManager

Android 中的 本地广播LocalBroadcastManager 文章目录 Android 中的 本地广播LocalBroadcastManager一、LocalBroadcastManager 的基本作用二 、LocalBroadcastManager 的基本使用1、包的导入&#xff08;1&#xff09;Android 源码中bp文件的导入&#xff1a;&#xff08;2&a…...

题目 1120: C语言训练-“水仙花数“问题2python详解)——练气三层后期

✨博主&#xff1a;命运之光 &#x1f984;专栏&#xff1a;算法修炼之练气篇&#xff08;C\C版&#xff09; &#x1f353;专栏&#xff1a;算法修炼之筑基篇&#xff08;C\C版&#xff09; &#x1f352;专栏&#xff1a;算法修炼之练气篇&#xff08;Python版&#xff09; ✨…...

sheng的学习笔记-【中】【吴恩达课后测验】Course 3 - 结构化机器学习项目 - 第二周测验

课程3_第2周_测验题 目录&#xff1a;目录 要解决的问题 ① 为了帮助你练习机器学习的策略&#xff0c;本周我们将介绍另一个场景&#xff0c;并询问你将如何行动。 ② 我们认为这个在机器学习项目中工作的“模拟器”将给出一个任务&#xff0c;即领导一个机器学习项目可能…...

基于Pytorch的驾驶员分心行为实时检测

本文使用深度学习和Pytorch(PyTorch 2.0.1\Torchvision 0.15.2)实时检测驾驶员的分心行为,并附录完整代码。 检测分心驾驶是现代汽车中最重要的功能之一。无论是自动驾驶汽车还是其它高端汽车,都配备了驾驶员监控系统,以持续跟踪驾驶员的行为。这对确保驾驶员保持目光在道路…...

【uniapp】小程序开发7:自定义组件、自动注册组件

一、自定义轮播图组件、自动注册 以首页轮播图组件为例。 1、创建组件文件src/components/my-swipper.vue 代码如下&#xff1a; <template><view><view class"uni-margin-wrap"><swiper class"swiper" circular :indicator-dots…...

Modbus转MQTT以太网网关MQT-802主要特点和典型应用

随着社会的快速发展&#xff0c;物联网已经潜移默化地深入工控行业的各个领域&#xff0c;其高效的资源整合和强大的数据采集能力&#xff0c;深受客户的喜爱。上海泗博为实现客户在云端平台接收处理世界万物的信息以及实现远程控制&#xff0c;精心打造一款全新物联网产品&…...

Go学习第五章——函数与包

Go学习第五章——函数与包 1 函数1.1 基本语法1.2 函数多返回值1.3 函数的可见性和包级函数1.4 函数调用机制底层原理1.5 值类型和引用类型1.6 注意事项和细节1.7 逃逸机制&#xff08;补&#xff0c;可不看&#xff09; 2 包2.1 快速入门2.2 包的使用细节 3 函数详细讲解3.1 递…...

【Python 常用脚本及命令系列 5 -- 如何使用 BeautifulSoup 解析CSDN网页表格中的数据】

文章目录 Python BeautifulSoup 介绍CSDN 网页表格解析开发问题总结 Python BeautifulSoup 介绍 BeautifulSoup是一个Python库&#xff0c;用于解析HTML和XML文档。它常常用于网络爬虫来提取网页中的信息。 以下是BeautifulSoup的一些主要特性&#xff1a; 解析HTML&#xff…...

OpenFeign实现分析、源码解析

什么是openfeign? 是springcloud全家桶的组件之一&#xff0c;其核心作用是为Rest API提供高效简洁的rpc调用方式。 为什么只定义接口而没有实现类&#xff1f; 源码解读&#xff08;省略&#xff09; 总结&#xff1a; 源码分析&#xff1a;如何发送http请求&#xff1f; …...

2023 10月最新Vmd 下载安装教程,WindowsLinux

文章目录 下载Vmdwindows版本安装LINUX版本安装 下载Vmd 谷歌搜索VMD 点击左下角download VMD 可选择对应版本 注&#xff1a;点击后会出现输入用户名和密码&#xff0c;由于我已注册&#xff0c;界面不见了&#xff0c;所以直接描述一下。 输入用户名和密码然后会出现让登记…...

Photoshop(PS)安装教程(图文教程超详细)

目录 一.简介 二.安装步骤 软件&#xff1a;PS版本&#xff1a;2023语言&#xff1a;简体中文大小&#xff1a;3.20G系统要求&#xff1a;Win10&#xff08;1903&#xff09;及以上版本&#xff0c;64位操作系统硬件要求&#xff1a;CPU2.0GHz 内存8G(或更高&#xff0c;不支…...

C++模版进阶

一、非类型模版参数 之前学习的模版&#xff0c;参数一般是某种类型&#xff0c;但其实非类型的参数也可以定义在模版里面&#xff0c;但也有一定的限制&#xff0c;只可以定义整形家族的参数&#xff0c;而且具有常量性 注意&#xff1a; 1. 浮点数、类对象以及字符串是不允…...

CloudCompare

CloudCompare 源码编译Windows 功能格式转换 源码编译 Windows 源码编译出来的默认基本不带几个插件&#xff0c;包括保存为 .las 的功能 可以直接从 https://www.danielgm.net/cc/ 下载编译好的版本&#xff0c;插件比较多。也有免安装版本 cmake -B build -S . -G "Vi…...

【算法小课堂】深入理解前缀和算法

前缀和是指某序列的前n项和&#xff0c;可以把它理解为数学上的数列的前n项和&#xff0c;而差分可以看成前缀和的逆运算。合理的使用前缀和与差分&#xff0c;可以将某些复杂的问题简单化。 我们通过一个例子来理解前缀和算法的优势&#xff1a; 一维前缀和&#xff1a; ww…...

元对象系统功能

元对象系统功能 建立工程 布局页面 布局页面 修改原件名称 建立元对象 函数作为接口 增加一些固定的属性 #------------------------------------------------- # # Project created by QtCreator 2023-10-24T21:54:44 # #----------------------------…...

【2024秋招】小米中间件后端开发一面2023-9-13-base武汉

1 自我介绍 2 快手实习 2.1 讲讲你写的curd启动器&#xff0c;做了哪些工作呢 答&#xff1a; 2.2 网上也有一些开源的curd代码生成器&#xff0c;你为什么需要自研呢&#xff08;重要&#xff09; 答&#xff1a; &#xff08;1&#xff09;这个必须得自研&#xff0c;因…...

SpringMVC Day 01:入门案例

前言 在我们的日常工作和学习中&#xff0c;Web 开发是一个无法回避的重要环节。而在 Java Web 开发领域&#xff0c;SpringMVC 无疑是一个重量级选手。它以其灵活性、强大功能和清晰的 MVC 结构&#xff0c;赢得了大量开发者的青睐。但是&#xff0c;对于初学者来说&#xff…...

docker、docker-compose安装教程,很详细

docker、docker-compose安装教程&#xff0c;很详细 一、卸载旧版1、查看有没有安装过旧版2、停止docker3、删除安装过docker的相关包4、删除docker相关的镜像和容器 二、docker安装1、设置阿里云镜像2、查看所有docker3、安装最新版本4、安装指定版本 三、使用前准备1、启动do…...

源代码转换:Tangible Software Solutions 23.10 Crack

Tangible Software Solutions The Most Accurate and Reliable Source Code Converters Convert between C#, Java, C, Python, & VB, while saving countless hours of painstaking work and valuable time.源代码转换 Key Benefits Saves valuable time Accurate and com…...

SAD notes

ESKF 总结 prediction 更新误差先验 F F F通过3.42来算 得到 这里有点绕的一点是: 误差状态的 F F F牵涉到名义状态, 而名义状态又需要在时间上推进更新 其中, F中的名义状态的推进通过公式3.41得到, (名义状态不考虑误差, 这一点从3.41d, 3.41e可以看出, 误差状态只考虑…...

[SQL开发笔记]BETWEEN操作符:选取介于两个值之间的数据范围内的值

一、功能描述&#xff1a; BETWEEN操作符&#xff1a;选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。 二、BETWEEN操作符语法详解&#xff1a; BETWEEN操作符语法&#xff1a; SELECT column1, column2,…FROM table_nameWHERE column BETWEEN val…...

Babylonjs学习笔记(三)——创建天空盒

书接上回&#xff0c;这里讨论创建天空盒&#xff01;&#xff01;&#xff01; // 天空盒const envTex CubeTexture.CreateFromPrefilteredData(./env/environmentSpecular.env,scene)scene.environmentTexture envTex;scene.createDefaultSkybox(envTex,true)scene.environ…...

【计算机网络】文件传输协议FTP和SFTP

1. 介绍 SFTP&#xff08;SSH文件传输协议&#xff09;和FTP&#xff08;文件传输协议&#xff09;都是用于在计算机之间传输文件的网络协议。FTP和SFTP都位于OSI模型中的应用层。这两种协议用于文件传输和管理&#xff0c;是应用层协议&#xff0c;因此它们工作在OSI模型的最…...

Python 编程语言的介绍

Python 是一种高级、动态类型的解释型语言。由 Guido van Rossum 于1989年底发明&#xff0c;并在1991年首次发布。Python 的设计哲学强调代码的可读性和简洁的语法&#xff0c;特别是使用缩进来表示代码块&#xff0c;这使得开发者能够用更少的代码表达想法。 基础概念: 语法…...

centos服务器搭建安装Gitlab教程使用教程

1、更新服务器&#xff1a; sudo yum update -y && sudo yum upgrade -y 2、下载Gitlab的RPM包 https://packages.gitlab.com/gitlab/gitlab-cece表示开源el表示centos 选64位el8对应CentOS8 本教程以centos8为例&#xff0c;在服务器中&#xff0c;下载centos8的…...

linux复习笔记02(小滴课堂)

linux下输入输出错误重定向&#xff1a; 输入重定向&#xff1a;< 一个大于号是进行了覆盖。 两个大于号是追加。 输出重定向可以用于以后日志打印。 错误重定向&#xff1a; 错误重定向是不把信息打印到屏幕上而是打印到指定文件中去&#xff1a; 输出重定向其实是用的1…...

AWVS漏洞扫描使用基础与介绍

漏洞扫描的基本概念和原理 漏洞扫描是指通过使用自动化工具和技术来检测和识别计算机系统和网络中可能存在的安全漏洞&#xff0c;用于帮助网络安全运维人员及时获取网络安全态势。漏洞扫描是网络安全中的重要环节&#xff0c;它可以帮助我们发现和修复网络中的安全漏洞&#x…...