拓扑排序和关键路径详解

目录

拓扑排序

关键路径

拓扑排序

如果有一个有向图的任意顶点都无法通过一些有向边回到身边,那么称这个有向图为有向无环图。

拓扑排序是将有向无环图的所有顶点排成一个线性序列,使得对图中的任意两个顶点u,v,如果存在边u->v,那么在序列中u一定在v前面,这个序列被称为拓扑序列。

拓扑排序实现的步骤如下:

(1)定义一个队列Q,并将所以入度为0的结点加入队列。

(2)取队首元素,输出。然后删去所有从它出发的边,并令这些边到达的顶点的入度减1,如果某个顶点的入度减为0,则将其加入队列。

(3)反复进行(2)操作,直到队列为空。如果队列为空时入过队的结点数目恰好为N,说明拓扑排序成功,图为有向无环图,否则,拓扑排序失败,图中有环。

可以用邻接表实现拓扑排序。显然,由于需要记录结点的入度,因此需要额外建立一个数组inDegree[maxn],并在程序一开始读入图时就记录好每个结点的入度。接下来只需要按上面说的步骤实现即可。

vector<int> G[maxn];
int n,m,inDegree[maxn];
bool topologicalSort(){int num=0;queue<int> q;for(int i=0;i<n;i++){if(inDegree[i]==0){q.push(i);}}while(!q.empty()){int u=q.front();q.pop();for(int i=0;i<G[u].size();i++){int v=G[u][i];inDegree[v]--;if(inDegree[i]==0){q.push(v);}}G[u].clear();num++;}if(num==n){return true;}else{return false;}
}

拓扑排序的一个重要的应用就是判断一个给定的图是否是有向无环图。如果有多个入度为0的顶点,选择编号最小的顶点,把么把queue改为priority_queue,并保持队首元素是优先队列的最小的元素即可。

关键路径

AOE网是指用带权的边集表示活动,而用顶点表示时间的有向图。关键路径就是AOE网中的最长路径,而把关键路径上的活动称为关键活动。

(1)计算一个事件的最早发生时间ve数组,可以使用拓扑排序实现,在拓扑排序访问到某个结点时,不是让它去找前驱结点来更新ve[i],而是使用ve[i]去更新其所有后继结点的ve值。

//拓扑排序 ,求ve数组 
stack<int> topOrder;
bool topOrdercalsort(){queue<int> q;for(int i=0;i<n;i++){if(inDegree[i]==0){q.push(i);}}while(!q.empty()){int u=q.front();q.pop();topOrder.push(u);for(int i=0;i<G[u].size();i++){int v=G[u][i].v;inDegree[v]--;if(inDegree[v]==0){q.push(v);}//用ve[u]来更新u的所有后继结点 if(ve[u]+G[u][i].w>ve[v]){ve[v]=ve[u]+G[u][i].w;}}}if(topOrder.size()==n){return true;}else{return false;}
}

(2)计算一个事件的最晚发生时间vl数组,可以通过逆拓扑排序来实现。可以通过颠倒拓扑排序来得到一组合法的逆拓扑排序。此时会发现,在上面实现拓扑排序时使用了栈来存储拓扑序列,那么只需要按顺序出栈就是逆拓扑序列。

fill(vl,vl+n,ve[n-1]);
while(!topOrder.empty()){int u=topOrder.top();topOrder.pop();for(int i=0;i<G[u].size();i++){int v=G[u][i].v;if(vl[v]-G[u][i].w<vl[u]){vl[u]=vl[v]-G[u][i].w;}}
}

(3)先求点,再夹边。下面是主体部分的代码。(适用汇点确定且唯一的情况)

//关键路径,不是有向无环图返回-1,否则返回关键路径长度 
int CriticalPath(){memset(ve,0,sizeof(ve));if(topOrdercalsort()==false){return -1;}fill(vl,vl+n,ve[n-1]);//直接使用topOrder出栈即为逆拓扑序列,求解vl数组 while(!topOrder.empty()){int u=topOrder.top();topOrder.pop();for(int i=0;i<G[u].size();i++){int v=G[u][i].v;if(vl[v]-G[u][i].w<vl[u]){vl[u]=vl[v]-G[u][i].w;}}}//遍历邻接表的所有边,计算活动的最早开始时间e和最迟开始时间lfor(int u=0;u<n;u++){for(int i=0;i<G[u].size();i++){int v=G[u][i].v,w=G[u][i].w;int e=ve[u],l=vl[v]-w;if(e==l){printf("%d->%d\n",u,v);}}} return ve[n-1];
}

在上面的代码中没有将活动的最早开始时间e和最晚开始时间l存储下来,因为一般来说e和l只是用来判断当前活动是否存在关键活动,没有必要单独存下来。如果确实想要存下来,只需要在结构体node中添加域e和l即可。

如果事先不知道汇点编号,最快的办法获得关键路径长度就是取ve数组的最大值。因为ve数组的含义是事件的最早开始时间,因此所有事件中ve最大的一定是最后一个事件,也就是汇点。于是只需要在fill函数之前添加一小段语句,然后改变vl函数初始值即可。

int maxLength=0;
for(int i=0;i<n;i++){if(ve[i]>maxLength){maxLength=ve[i];}
}
fill(vl,vl+n,maxLength);

即便图中有多条关键路径,但是如果题目只要求输出关键活动,按照上面的写法就可以。如果要求输出所有的关键路径,就需要把关键活动存下来,方法就是新建一个邻接表,当确定边u->v是关键活动时,就将它加入邻接表。这样最后生成的邻接表就是所有关键路径合成的图,可以用dfs遍历来获取所有关键路径。

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

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

相关文章

VMware ESXi 8.0U2c macOS Unlocker OEM BIOS ConnectX-3 网卡定制版 (集成驱动版)

VMware ESXi 8.0U2c macOS Unlocker & OEM BIOS ConnectX-3 网卡定制版 (集成驱动版) 发布 ESXi 8.0U2 集成驱动版&#xff0c;在个人电脑上运行企业级工作负载 请访问原文链接&#xff1a;https://sysin.org/blog/vmware-esxi-8-u2-sysin/&#xff0c;查看最新版。原创作…

UE5.2打包安卓

目录 简介: 一. 根据官网配置 二. 手动定位SDK路径 三: 设置Android基本信息 四: 设置KeyStore 五: 开始打包 六:其他 七. 总结 简介: UE5.2 打包安卓是指将使用 Unreal Engine 5.2 开发的项目编译为可在安卓设备上运行的安装包。 以下是一般的打包步骤&#xff1a; 安装…

centos7 xtrabackup mysql 基本测试(3)---虚拟机环境 安装mysql

centos7 xtrabackup mysql 基本测试&#xff08;3&#xff09;—虚拟机环境 安装mysql centos7 安装 mysql5.7 可以在运行安装程序之前导入密钥&#xff1a; sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022第一步、下载MySQL 安装包&#xff1a; sudo w…

Web前端CreateJS:探索、深化与应用

Web前端CreateJS&#xff1a;探索、深化与应用 在Web前端的世界里&#xff0c;CreateJS是一套功能强大的JavaScript库&#xff0c;它让开发者能够轻松创建富交互性的动画、游戏和应用程序。本文将从四个方面、五个方面、六个方面和七个方面深入探讨CreateJS的魅力与应用。 四…

Spring Cloud全家桶(上)【Nacos、OpenFeign、LoadBalancer、GateWay、金丝雀灰色发布】

0.零基础入门微服务实战课 1.微服务和 Spring Cloud1.1 什么是微服务&#xff1f;1.2 什么是 Spring Cloud&#xff1f;1.3 微服务 VS Spring Cloud 2.为什么要学微服务&#xff1f;3.Spring Cloud 组件介绍1.什么是 Nacos?1.1 Nacos 功能1.1.1 配置中心1.1.2 注册中心 1.2 Na…

HashMap底层源码分析

目录 一、知识点二、数据结构三、resize() 扩容方法四、putVal() 添加数据方法五、remove() 删除方法六、removeTreeNode() 退化链表方法 一、知识点 加载因子: HashMap 的默认的加载因子: 0.75&#xff0c;用来限定阈值&#xff08;用于控制 HashMap 的饱和度&#xff09; 阈值…

红酒保存中的摆放方式:倾斜瓶身的重要性

在探讨云仓酒庄雷盛红酒的保存方法时&#xff0c;我们不得不提及一个关键的细节&#xff1a;瓶身的倾斜。许多人可能认为红酒的保存方式仅仅是温度控制和存储环境的湿度问题&#xff0c;然而实际上&#xff0c;摆放方式同样至关重要。雷盛红酒在保存过程中&#xff0c;需要一个…

安川机器人MA1440减速机维修方法

一、安川机械臂减速器维修方法 1. 齿轮磨损维修 对于轻微磨损的齿轮&#xff0c;可以通过重新调整啮合间隙来恢复性能。对于严重磨损的齿轮&#xff0c;需要更换新安川MA1440机械手齿轮箱齿轮。 2. 轴承损坏维修 对于损坏的轴承&#xff0c;需要更换新的轴承。在更换过程中&…

Linux/Ubuntu/Debian常用服务管理命令

Linux/Ubuntu/Debian常用服务管理命令 在 Linux 系统中&#xff0c;服务管理是系统管理员日常维护工作的重要组成部分。通过一些常用的命令&#xff0c;我们可以查看服务状态、启动或停止服务、重启服务等。掌握这些命令&#xff0c;可以让系统管理工作更加高效和便捷。 1. s…

省市县选择三级联动(使用高德API实现)

省市县选择如果自己实现是比较麻烦的&#xff0c;最近发现可以使用高德实现省市县联动选择&#xff0c;实现后来记录一下供大家参考。 文章目录 最终效果&#xff1a;一、准备工作二、完整页面代码 最终效果&#xff1a; 实现单次点击获取省市县名称&#xff0c;选择完成后返回…

Java中的多态性

形成多态性前提&#xff1a;有继承关系&#xff0c;且子类重写父类的方法 场景 一般用于方法的参数传递&#xff0c;形参声明父类&#xff0c;实参传入子类&#xff0c;这样在方法体中调用被重写方法的时候&#xff0c;实际执行的是子类重写的方法&#xff0c;以此形成多态&…

web端即时通信技术

web端即时通信技术 对于IM/消息推送这类即时通讯系统而言&#xff0c;系统的关键就是“实时通信”能力。所谓实时通信有以下两层含义 客户端可以主动向服务端发送信息。 当服务端内容发生变化时&#xff0c;服务端可以实时通知客户端。 HTTP局限 Http是客户端/服务器模式中…

高可用系统的设计原则

降级 在软件开发和系统设计中&#xff0c;降级&#xff08;Degradation&#xff09;是一种应对系统压力或异常情况的策略&#xff0c;旨在保持系统的核心功能运行&#xff0c;即使这可能意味着临时牺牲一些非关键功能。降级模式通常分为主动降级和被动降级两种类型&#xff1a…

免费分享:1901-2020全球气候数据集(附下载办法)

长期的全球其后数据不仅能够揭示长期的气候趋势&#xff0c;还为农业、水资源管理、公共卫生等多个领域的决策提供科学依据&#xff0c;对于推动可持续发展具有重要意义。 数据集简介 CRU TS&#xff08;Climatic Research Unit gridded Time Series&#xff09;数据集&#…

【Kafka】SpringBoot整合Kafka详细介绍及代码示例

Kafka介绍 Apache Kafka是一个分布式流处理平台。它最初由LinkedIn开发&#xff0c;后来成为Apache软件基金会的一部分&#xff0c;并在开源社区中得到了广泛应用。Kafka的核心概念包括Producer、Consumer、Broker、Topic、Partition和Offset。 Producer&#xff1a;生产者&a…

车载android开发 carservice(一)

车载android开发 carservice是什么? 车载Android开发中的CarService是一个专门为汽车环境设计的系统服务。CarService通常是Android Automotive OS的一部分,提供一系列API和框架,允许开发人员构建与汽车相关的应用和服务。 以下是CarService的一些主要功能和作用: 车辆数…

宽睿数字平台兼容TDengine 等多种数据库,提供行情解决方案

小T导读&#xff1a;最近&#xff0c;涛思数据与宽睿金融宣布了一项重要合作。在此之前&#xff0c;宽睿金融对 TDengine 进行了性能测试&#xff0c;并根据测试报告的结果&#xff0c;决定将 TDengine 接入宽睿数字平台&#xff0c;以提升高密度行情处理效率。本文将详细介绍此…

百元开放式耳机性价比推荐,全网5款爆火产品实测!

耳机作为我们日常生活中不可或缺的一部分&#xff0c;它的性能、配置及形态也在不停的优化。目前开放式耳机是耳机中最为热门的一款产品&#xff0c;以其不入耳的的设计迅速占领耳机市场&#xff0c;最主要是因为自身佩戴的舒适度有大幅度提升。人们更加注重生活的质量&#xf…

Apollo9.0 PNC源码学习之Control模块(五)—— 基于LQR的横向控制

前面文章&#xff1a; Apollo9.0 PNC源码学习之Control模块&#xff08;一&#xff09; Apollo9.0 PNC源码学习之Control模块&#xff08;二&#xff09; Apollo9.0 PNC源码学习之Control模块&#xff08;三&#xff09; Apollo9.0 PNC源码学习之Control模块&#xff08;四&…

通信原理抽样定理和PAM调制解调硬件实验

一、实验目的 1. 加深理解抽样定理&#xff1b; 2. 加深理解脉冲幅度调制的原理。 二、实验内容 1. 观测PAM平顶抽样波形&#xff1b; 2. 观测PAM自然抽样波形及解码后波形。 三、实验器材 1. 双踪示波器&#xff1b; 2. 通信原理实验箱信号源模块、①号模块。 四、实…