数据结构(六)——图的应用

6.4 图的应用

6.4.1 最小生成树

对于⼀个带权连通⽆向图G = (V, E),⽣成树不同,每棵树的权(即树中所有边上的权值之和)也可能不同。设R为G的所有⽣成树的集合,若T为R中边的权值之和最小的生成树,则T称为G的最小生成树(Minimum-Spanning-Tree, MST)。

最小生成树可能有多个,但边的权值之和总是唯一且最小的
最小生成树的边数=顶点数–1。砍掉一条则不连通,增加一条边则会出现回路

求最小生成树
Prim算法(普里姆):
从某一个顶点开始构建生成树;
每次将代价最小的新顶点纳入生成树,
直到所有顶点都纳入为止。

Kruskal算法(克鲁斯卡尔):
每次选择一条权值最小的边,使这条边的两头连通(原本已经连通的就不选)
直到所有结点都连通


Prim算法的实现思想
第1轮:循环遍历所有个结点,找到lowCost最低的,且还没加入树的顶点
第2轮︰循环遍历所有个结点,找到lowCost最低的,且还没加入树的顶点
第3轮:循环遍历所有个结点,找到lowCost最低的,且还没加入树的顶点
第4轮:循环遍历所有个结点,找到lowCost最低的,且还没加入树的顶点
第5轮:循环遍历所有个结点,找 到lowCost最低的,且还没加入树的顶点

Kruskal 算法的实现思想
第1轮:检查第1条边的两个顶点是否 连通(是否属于同⼀个集合)
第2轮:检查第2条边的两个顶点是否 连通(是否属于同⼀个集合)
第3轮:检查第3条边的两个顶点是否 连通(是否属于同⼀个集合)
第4轮:检查第4条边的两个顶点是否 连通(是否属于同⼀个集合)
第5轮:检查第5条边的两个顶点是否 连通(是否属于同⼀个集合)
第6轮:检查第6条边的两个顶点是否 连通(是否属于同⼀个集合)

6.4.2_1 最短路径问题_BFS算法


BFS求无权图的单源最短路径

#define MAX_LENGTH 2147483647			//地图中最大距离,表示正无穷//求顶点u到其他顶点的最短路径
void BFS_MIN_Disrance(Graph G,int u){//d[i]表示从u到i结点的最短路径for(i=0; i<G.vexnum; i++){visited[i]=FALSE;				//初始化访问标记数组d[i]=MAX_LENGTH;				//初始化路径长度path[i]=-1;						//初始化最短路径记录}InitQueue(Q);						//初始化辅助队列d[u]=0;visites[u]=TREE;EnQueue(Q,u);while(!isEmpty[Q]){					//BFS算法主过程DeQueue(Q,u);					//队头元素出队并赋给ufor(w=FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w)){if(!visited[w]){            //w为u的尚未访问的邻接顶点d[w]=d[u]+1;            //路径长度+1path[w]=u;              //最短路径应从u到wvisited[w]=TREE;        //设已访问标记EnQueue(Q,w);			//顶点w入队}}}
}

6.4.2_2 最短路径问题_Dijkstra算法

使用 Dijkstra算法求最短路径问题,需要使用三个数组:
final[]数组用于标记各顶点是否已找到最短路径。
dist[]数组用于记录各顶点到源顶点的最短路径长度。
path[]数组用于记录各顶点现在最短路径上的前驱。

算法思想:循环遍历所有结点,找到还没确定最短路径、且dist最小的顶点Vi,令final[i]=ture。
检查所有邻接自Vi的顶点,若其final值为false,则更新dist和path信息。

#define MAX_LENGTH = 2147483647;// 求顶点u到其他顶点的最短路径
void BFS_MIN_Disrance(Graph G,int u){for(int i=0; i<G.vexnum; i++){		//初始化数组final[i]=FALSE;dist[i]=G.edge[u][i];if(G.edge[u][i]==MAX_LENGTH || G.edge[u][i] == 0)path[i]=-1;elsepath[i]=u;final[u]=TREE;}for(int i=0; i<G.vexnum; i++){int MIN=MAX_LENGTH;int v;// 循环遍历所有结点,找到还没确定最短路径,且dist最⼩的顶点vfor(int j=0; j<G.vexnum; j++){if(final[j]!=TREE && dist[j]<MIN){MIN = dist[j];v = j;}}final[v]=TREE;// 检查所有邻接⾃v的顶点路径长度是否最短for(int j=0; j<G.vexnum; j++){if(final[j]!=TREE && dist[j]>dist[v]+G.edge[v][j]){dist[j] = dist[v]+G.edge[v][j];path[j] = v;}}}
}



Dijkstra算法能够很好的处理带权图的单源最短路径问题,但不适⽤于有负权值的带权图。

6.4.2_3 最短路径问题_Floyd算法

Floyd算法:求出每⼀对顶点之间的最短路径,使⽤动态规划思想,将问题的求解分为多个阶段。

Floyd算法使用到两个矩阵:
dist[]:目前各顶点间的最短路径。
path[]:两个顶点之间的中转点。

//...准备工作,根据图的信息初始化矩阵A和pathfor(k=0;k<n;k++){                //考虑以Vk作为中转点for(i=0;i<n;i++){            //遍历整个矩阵,i为行号,j为列号for(j=0;j<n;j++){if(A[i][j]>A[i][k]+A[k][j]){    //以Vk为中转地按的路径更短A[i][j]=A[i][k]+A[k][j];    //更新最短路径长度path[i][j]=k;               //中转点}}}}



 
Floyd算法不能解决带有“负权回路”的图(有负权值的边组成回路),这种图有可能没有最短路径

最短路径算法比较:

BFS算法Dijkstra算法 Floyd算法
无权图
带权图
带负权值的图
带负权回路的图
时间复杂度O(|V|^2)或O(|V|+|E|)O(|V|^2)O(|V|^3)
通常用于求无权图的单源最短路径 求带权图的单源最短路径求带权图中各顶点间的最短路径

6.4.3 有向无环图描述表达式

有向无环图:若一个有向图中不存在环,则称为有向无环图,简称DAG图(Directed Acyclic Graph)




      
解题方法


练习

6.4.4 拓扑排序

AOV网(Activity on vertex Network,用顶点表示活动的网):
用DAG图(有向无环图)表示一个工程。顶点表示活动,有向边<Vi,Vj>表示活动Vi必须先于活动Vj进行

拓扑排序︰在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序:
①每个顶点出现且只出现一次。
②若顶点A在序列中排在顶点B的前面,则在图中不存在从顶点B到顶点A的路径。

或定义为:拓扑排序是对有向无环图的顶点的一种排序,它使得若存在一条从顶点A到顶点B的路径,则在排序中顶点B出现在顶点A的后面。每个AOV网都有一个或多个拓扑排序序列。

拓扑排序的实现:
① 从AOV网中选择⼀个没有前驱(入度为0)的顶点并输出。
② 从网中删除该顶点和所有以它为起点的有向边。
③ 重复①和②直到当前的AOV网为空或当前网中不存在无前驱的顶点为止


代码实现拓扑排序

#define MaxVertexNum 100			//图中顶点数目最大值typedef struct ArcNode{				//边表结点int adjvex;						//该弧所指向的顶点位置struct ArcNode *nextarc;		//指向下一条弧的指针
}ArcNode;typedef struct VNode{				//顶点表结点VertexType data;				//顶点信息ArcNode *firstarc;				//指向第一条依附该顶点的弧的指针
}VNode,AdjList[MaxVertexNum];typedef struct{AdjList vertices;				//邻接表int vexnum,arcnum;				//图的顶点数和弧数
}Graph;								//Graph是以邻接表存储的图类型// 对图G进行拓扑排序
bool TopologicalSort(Graph G){InitStack(S);					//初始化栈,存储入度为0的顶点for(int i=0;i<g.vexnum;i++){if(indegree[i]==0)Push(S,i);				//将所有入度为0的顶点进栈}int count=0;					//计数,记录当前已经输出的顶点数while(!IsEmpty(S)){				//栈不空,则存入Pop(S,i);					//栈顶元素出栈print[count++]=i;			//输出顶点ifor(p=G.vertices[i].firstarc;p;p=p=->nextarc){//将所有i指向的顶点的入度减1,并将入度为0的顶点压入栈v=p->adjvex;if(!(--indegree[v]))Push(S,v);			//入度为0,则入栈}}if(count<G.vexnum)return false;				//排序失败,有向图中有回路elsereturn true;				//拓扑排序成功
}

拓扑排序 每个顶点都需要处理一次 每条边都需要处理一次
时间复杂度:O(|V|+|E|)
若采用邻接矩阵,则需O(|V^2|)

逆拓扑排序
对一个AOV网,如果采用下列步骤进行排序,则称之为逆拓扑排序:
①从AOV网中选择一个没有后继(出度为O)的顶点并输出。
②从网中删除该顶点和所有以它为终点的有向边。
③重复①和②直到当前的AOV网为空。

逆拓扑排序的实现(DFS算法)

void DFSTraverse(Graph G){    //对图G进行深度优先遍历for(v=0; v<G.vexnum;++V)visited[v]=FALSE;     //初始化已访问标记数据for(v=;v<G.vexnum; ++V)   //本代码中是从v=0开始遍历if(!visited[v])DFS(G,v);
}void DFS(Graph G,int v){     //从顶点v出发,深度优先遍历图Gvisited [v]=TRUE;        //设已访问标记for(w=FirstNeighbor(G,v);w>=0 ; w=NextNeighor(G,v,w))if(!visited[w]){     //w为u的尚未访问的邻接顶点DFS(G,w);}//ifprint(v);                //输出顶点
}

6.4.5 关键路径

AOE 网:在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销(如完成活动所需的时间),称之为用边表示活动的网络,简称 AOE 网 (Activity On Edge NetWork)。

AOE网具有以下两个性质:
①只有在某顶点所代表的事件发⽣后,从该顶点出发的各有向边所代表的活动才能开始;
②只有在进⼊某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发⽣。 
在 AOE 网中仅有⼀个入度为 0 的顶点,称为开始顶点(源点),它表示整个⼯程的开始; 也仅有⼀个出度为 0 的顶点,称为结束顶点(汇点),它表示整个⼯程的结束。

在AOE网中,有些活动是可以并行进行的。从源点到汇点的有向路径可能有多条,所有路径中,具有最大路径长度的路径称为关键路径,而把关键路径上的活动称为关键活动。完成整个工程的最短时间就是关键路径的长度,若关键活动不能按时完成,则整个工程的完成时间就会延长。

寻找冠军活动时所用到的几个参量的定义:

1. 事件 vk的最早发生时间 ve(k):决定了所有从vk 开始的活动能够开工的最早时间。
2. 事件 vk的最迟发⽣时间 vl(k):它是指在不推迟整个工程完成的前提下,该事件最迟必须发⽣的时间。
3.活动ai的最早开始时间e(i):指该活动弧的起点所表示的事件的最早发生时间。
4.活动ai的最迟开始时间l(i):它是指该活动弧的终点所表示事件的最迟发生时间与该活动所需时间之差。
5.活动 ai的时间余量d(i)=l(i)−e(i),表示在不增加完成整个⼯程所需总时间的情况下,活动ai可以拖延的时间若⼀个活动的时间余量为零,则说明该活动必须要如期完成,d(i)=0 即l(i)=e(i) 的活动ai是关键活动,由关键活动组成的路径就是关键路径。

求关键路径的步骤:
1.求所有事件的最早发生时间ve():按拓扑排序序列,依次求各个顶点的ve(k), ve(源点)=0, ve(k) =Max{vef)+W eight(vj , vk )},vj为vk的任意前驱。
2.求所有事件的最迟发生时间vl():按逆拓扑排序序列,依次求各个顶点的 vl(k),vl(汇点)= ve(汇点),vl(k)=Min{vl(j)- W eight(vk , vi)},v为Vv\k 的任意后继。
3.求所有活动的最早发生时间e():若边<Vk ,Vj>表示活动a;,则有e(i)=ve(k)。
4.求所有活动的最迟发生时间1():若边<Vk,Vj >表示活动a,则有l(i)= vl(j)- Weight(vi , vj)。
5.求所有活动的时间余量d(): d(i)= l(i)-e(i)。

关键活动、关键路径的特性:
1.若关键活动耗时增加,则整个工程的工期将增长。
2.缩短关键活动的时间,可以缩短整个工程的工期。
3.当缩短到一定程度时,关键活动可能会变成非关键活动。
4.可能有多条关键路径,只提高一条关键路径上的关键活动速度并不能缩短整个工程的工期,只有加快那些包括在所有关键路径上的关键活动才能达到缩短工期的目的。

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

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

相关文章

怎样把学浪上的视频保存到电脑

怎样把学浪上的视频保存到电脑,这里给大家一个工具,专门用来下载学浪上的视频 这个工具叫做小浪助手.exe 我已经打包好了,有需要的自己取一下 链接&#xff1a;https://pan.baidu.com/s/1y7vcqILToULrYApxfEzj_Q?pwdkqvj 提取码&#xff1a;kqvj --来自百度网盘超级会员V…

【三维重建】3D Gaussian Splatting:实时的神经场渲染

文章目录 摘要一、前言二、相关工作1.传统的场景重建与渲染2.神经渲染和辐射场3.基于点的渲染和辐射场4.*什么是 Tile-based rasterizer (快速光栅化) 三、OVERVIEW四、可微的三维高斯 Splatting五、三维高斯 自适应密度控制的优化1.优化2.高斯的自适应控制 六、高斯分布的快速…

计算机网络—HTTP协议:深入解析与应用实践

​ &#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;ヒステリックナイトガール 1:03━━━━━━️&#x1f49f;──────── 5:06 &#x1f504; ◀️ ⏸ ▶️ ☰…

Photoshop 2024 中文---专业图像处理软件的又一次飞跃

Photoshop 2024是一款功能强大的图像处理软件&#xff0c;广泛应用于创意设计和图像处理领域。它提供了丰富的绘画和编辑工具&#xff0c;包括画笔、铅笔、颜色替换、混合器画笔等&#xff0c;使用户能够轻松进行图片编辑、合成、校色、抠图等操作&#xff0c;实现各种视觉效果…

如何使用极狐GitLab 启用自动备份功能

本文作者&#xff1a;徐晓伟 GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 本文主要讲述了如何极狐GitLab 自…

利用Node.js实现拉勾网数据爬取

引言 拉勾网作为中国领先的互联网招聘平台&#xff0c;汇集了丰富的职位信息&#xff0c;对于求职者和人力资源专业人士来说是一个宝贵的数据源。通过编写网络爬虫程序&#xff0c;我们可以自动化地收集这些信息&#xff0c;为求职决策和市场研究提供数据支持。Node.js以其非阻…

基于Python的豆瓣电影评分可视化,豆瓣电影评分预测系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

【stm32】I2C通信外设

【stm32】I2C通信外设 概念部分 如果简单应用&#xff0c;选择软件I2C。如果对性能指标要求比较高 选择硬件I2C 有硬件电路自动反转引脚电平&#xff0c;软件只需要写入控制寄存器CR和数据寄存器DR 为了实时监控时序的状态&#xff0c;还要读取状态寄存器SR 写入控制寄存器CR…

nodeJs 实现视频的转换(超详细教程)

前段时间拿到一个视频是4k的&#xff0c;没法播放&#xff0c;于是通过 node.js 和 ffmpeg 实现了视频的转换。在win10 系统下实现。 所需工具 node 16.19 直接安装 ffmpeg-5.1.1-essentials_build 解压后重名 ffmpeg 放到C盘 然后配置下环境变量 Git-2.42.0.2-64-bit 直接…

一键更换ip地址命令的应用方法

在数字化时代&#xff0c;IP地址作为网络设备的标识符&#xff0c;其重要性不言而喻。然而&#xff0c;在某些特定场景下&#xff0c;我们可能需要频繁地更换IP地址&#xff0c;如网络爬虫、隐私保护或测试环境等。这时&#xff0c;一键更换IP地址的命令就显得尤为重要。虎观代…

51单片机实验02- P0口流水灯实验

目录 一、实验的背景和意义 二、实验目的 三、实验步骤 四、实验仪器 五、实验任务及要求 1&#xff0c;从led4开始右移 1&#xff09;思路 ①起始灯 &#xff08;led4&#xff09; ②右移 2&#xff09;效果 3&#xff09;代码☀ 2&#xff0c;从其他小灯并向右依…

美易官方:现在不考虑降息,可能需要进一步加息

美联储密集放鹰&#xff1a;现在不考虑降息&#xff0c;可能需要进一步加息 达拉斯联储主席洛根&#xff08;Lorie Logan&#xff09;周五表示&#xff0c;考虑降息还为时过早&#xff0c;理由是近期通胀数据高企&#xff0c;且有迹象显示&#xff0c;借贷成本对经济的拖累可能…

人脸识别:Arcface--loss+code

之前只接触过传统方法的人脸识别算法&#xff0c;本以为基于深度学习的方法会使用对比损失之类的函数进行训练&#xff0c;但是Arcface算法基于softmax进行了创新&#xff0c;本文未深究其详细的loss公式原理&#xff0c;在大致明白其方向下&#xff0c;运行了代码&#xff0c;…

太阳能光伏储能系统:全周期一站式解决方案

随着全球能源结构的不断变革&#xff0c;清洁能源的重要性日益凸显。太阳能光伏储能系统作为一种高效、环保的能源解决方案&#xff0c;正逐渐成为推动能源转型的关键力量。本文将详细介绍太阳能光伏储能系统的全周期一站式解决方案&#xff0c;以期为读者提供全面、深入的了解…

MacOS - brew 和 brew cask 有什么区别?

brew 是 ruby 的包管理&#xff0c;后来看 yangzhiping 的博客介绍了 brew cask&#xff0c;感觉 cask 是更好的关联关系管理&#xff0c;但是&#xff0c;我后来使用过程中&#xff0c;发现很多软件 brew cask 里没有&#xff0c;但是 brew 里面倒是挺多&#xff01;今天来给说…

SpringBoot(48)-使用 SkyWalking 进行分布式链路追踪

Spring Boot&#xff08;48&#xff09;- 使用 SkyWalking 进行分布式链路追踪 介绍 在分布式系统中&#xff0c;了解各个服务之间的调用关系和性能表现是非常重要的。SkyWalking 是一款开源的分布式系统监控与分析平台&#xff0c;能够帮助我们实现分布式系统的链路追踪、性…

Java流操作解析:深度剖析中间操作、终端操作与并行处理机制

文章目录 一、中间操作1.1 过滤&#xff08;filter&#xff09;1.2 映射&#xff08;map&#xff09;1.3 排序&#xff08;sorted&#xff09;1.4 去重&#xff08;distinct&#xff09; 二、 终端操作2.1 收集&#xff08;collect&#xff09;2.2 计数&#xff08;count&#…

使用 ChatGPT 创建在线课程:一步一步指南与提示模板

原文&#xff1a;Creating Online Courses with ChatGPT 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 谢谢 作为对你支持的感谢&#xff0c;随意定制本书中列出的任何提示&#xff0c;并将其作为你自己的重新销售。是的&#xff0c;对你免费。 它们都结构良好且用…

二叉树算法练习day.2

102.二叉树的层序遍历 链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目描述&#xff1a; 给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&a…

AcWing 312. 乌龟棋(每日一题)

原题链接&#xff1a;312. 乌龟棋 - AcWing题库 小明过生日的时候&#xff0c;爸爸送给他一副乌龟棋当作礼物。 乌龟棋的棋盘只有一行&#xff0c;该行有 N 个格子&#xff0c;每个格子上一个分数&#xff08;非负整数&#xff09;。 棋盘第 1 格是唯一的起点&#xff0c;第…