关键路径算法(Critical Path)

news2024/11/17 4:36:44

这个算法《算法导论》中并没有提及,很多书和博客说的有点奇怪,所以写本文作为笔记。

关键路径是什么

关键路径的定义非常简单:就是一个图中,权值之和最大的路径就是关键路径。

那么就可以知道关键路径不唯一

为什么有关键路径

关键路径的来源和拓扑排序是一样的,都是将一项较大的工程划分为多个子工程,然后表示子工程之间的关系的。

关键路径和拓扑排序不同之处在于:

  • 拓扑排序强调子工程之间的先后顺序(说依赖关系可能更恰当一些),比如必须做完a才能做c
  • 关键路径在拓扑排序的基础上,还加入了时间关系。这个时间关系不光是子工程之间的,也包括子工程和整体之间的。

比如必须做完ab才能做c,做完cd才能做e,而a需要 3 天,b需要 5 天,c需要 1 天,d需要 4 天。

  • 那么整体上来说,
    • c必须要等五天后才可以开始做,这个 5 天有个术语叫c最早发生时间,也就是c最快要什么时候开始。 d最早发生时间0,因为没有前置事件,同理ab也是 0。
    • d最快可以一开始就做,因为没有前置事件,但是最晚开始的时间,只能推迟一天,不然加上做的 4 天,1+4=5,会导致c做完了,d还没做完,就会耽误e的发生。而这个 1 天的术语叫做最迟发生时间,也就是d最晚要什么时候开始。
    • 需要注意这里的时间由于是从0开始的,等五天后得到的是2+3=5,相当于第六天开始,写算法的时候要注意这点。

  • 局部来说,a可以延期 2 天再开始,d可以延期 1 天,也都不会耽误进度。在关键路径中,这个可以延期的时间也有个术语叫做时间余量。可以看到就是最迟发生时间 - 最早发生时间,或者说结束时间-(最早结束时间-子工程耗时),明白含义之后,公式和变形就很好记了。

当然稍微复杂一些的最迟发生时间就很难简单看出来了,因为前置条件太复杂,所以要有个计算流程,避免人为出错。

如何求得关键路径

求关键路径的方法很多书上说的很难似的,其实很简单。以下图为例:

请添加图片描述

源点(开始的点)选择是V1

AOE 关键路径图中,顶点是子工程的开始,边是事件。箭头可以理解为时间的发展方向。这与拓扑排序不同。

第一步:求子工程之间的关系和最早发生时间

关键路径的来源和拓扑排序是一样的,第一步当然是先找到子工程之间的依赖关系,在这个过程中,可以顺道加上路径的权值(在上面的例子中,也就是天数)。

那么可以得到一个序列和每个节点的最早开始时间 V e ( i ) V_e(i) Ve(i)。也就是路径权值相加最大值,具体来说,就是多个前驱的时候选最早开始时间+权值最大的一个,刚好与最短路径算法相反:

V 1 V_1 V1 V 2 V_2 V2 V 3 V_3 V3 V 4 V_4 V4 V 5 V_5 V5 V 6 V_6 V6
V e ( i ) V_e(i) Ve(i)032668

下标e表示early,早嘛。

第二步:求子工程最迟发生时间(逆拓扑排序)

拓扑排序是先从无前驱的节点开始(没有前置条件),然后删点删边,一次次后得到序列。而逆拓扑排序是从无后继节点开始(不会影响其他节点)。

这里概念听上去就很乱,但是实际上你可以重现画一个图,前驱改后继,后继改前驱(箭头取反),然后从得到的最大值(这里是8)进行拓扑排序和记录时间(加变减),得到的结果一样的,远比书上的方法简单快速,不易出错。

如果你看不到下面的,就按照上面的说法,自己拿草稿纸画一下,立马就懂了。

那么可以得到一个序列和对应的最迟开始时间 V l ( i ) V_l(i) Vl(i)。具体每步就是从尾部开始,每个节点的最迟开始时间 V l ( i ) V_l(i) Vl(i)上一个节点的最后开始时间 - 前驱的最小权值

上面得到的最早开始时间序列为:

V 1 V_1 V1 V 2 V_2 V2 V 3 V_3 V3 V 4 V_4 V4 V 5 V_5 V5 V 6 V_6 V6
V e ( i ) V_e(i) Ve(i)032668

最后一个节点的最迟开始时间和最早开始时间一样:

V 1 V_1 V1 V 2 V_2 V2 V 3 V_3 V3 V 4 V_4 V4 V 5 V_5 V5 V 6 V_6 V6
V e ( i ) V_e(i) Ve(i)032668
V l ( i ) V_l(i) Vl(i)8

V 6 V_6 V6逆拓扑排序消除 V 4 V_4 V4 V 5 V_5 V5对应的权值为21(就一个,不分大小了就)。8减去可得:

V 1 V_1 V1 V 2 V_2 V2 V 3 V_3 V3 V 4 V_4 V4 V 5 V_5 V5 V 6 V_6 V6
V e ( i ) V_e(i) Ve(i)032668
V l ( i ) V_l(i) Vl(i)678

然后逆拓扑排序 V 2 V_2 V2 V 3 V_3 V3,要求节点最晚发生时间-权值最小,那么对应最小权值为24(都从 V 4 V_4 V4),6减去这两个值可得:

这里是为了说明,实际上算出来直接选就行了,“最小权值”不需要求出来

V 1 V_1 V1 V 2 V_2 V2 V 3 V_3 V3 V 4 V_4 V4 V 5 V_5 V5 V 6 V_6 V6
V e ( i ) V_e(i) Ve(i)032668
V l ( i ) V_l(i) Vl(i)42678

最后减去最小后继权值2(从 V 3 V_3 V3),2减去这个值可得:

V 1 V_1 V1 V 2 V_2 V2 V 3 V_3 V3 V 4 V_4 V4 V 5 V_5 V5 V 6 V_6 V6
V e ( i ) V_e(i) Ve(i)032668
V l ( i ) V_l(i) Vl(i)042678

第三步:作差得到时间余量,为0的就是关键节点,组成关键路径

V 1 V_1 V1 V 2 V_2 V2 V 3 V_3 V3 V 4 V_4 V4 V 5 V_5 V5 V 6 V_6 V6
V e ( i ) V_e(i) Ve(i)032668
V l ( i ) V_l(i) Vl(i)042678
V l ( i ) − V e ( i ) V_l(i)-V_e(i) Vl(i)Ve(i)010010

那么关键路径就为: V 1 − > V 3 − > V 4 − > V 6 V_1 -> V_3 -> V_4 -> V_6 V1>V3>V4>V6。很多图的关键路径不能这么算,因为可能有多个路径的权值之和都是最大值,也就是说有多个关键路径,那么就要自己看一下图了,选一个好算的。(也就是下一节的内容)

快速计算

按照上面的方法很烦,每次计算都要算两个序列,我又不是电脑,算那么多很慢的,所以可以直接找最大后继最小前驱

以 2019 年 408 的一道题来说:找出下面 AOE 网中,活动 d最早开始时间和最晚开始时间。

请添加图片描述

你可以算两个序列,但是那太麻烦了。

开始时间就是前面的节点,也就是2。那就算从12之间最大的路径和最长路径减去26之间的最小路径。

那么眼一打最早开始时间就是12

最晚开始时间可能需要算一下16的最大路径,算出来是27。然后继续用眼一打,26之间的最小路径为13,那么27-13=14。所以最晚开始时间是14

怕看错,就把每个路径写出来,然后选出最大/最小的一个,有些路径大题就是这么答的。

这个原理是关键路径的定义:权值之和最大的路径就是关键路径。所以关键路径不唯一,我们可以利用这一点选一个好算的路径就行了。

关键路径有何用

我们前文说,关键路径表示的是工程所需的最大时间,那么就可以使用关键路径得知如何改进时间。

如果改进一件事的时间,可以让所有关键路径(也就是最大值)减少,那么改进这件事所需的时间,就可以减少整个工程所需的时间。

希望能帮到有需要的人~

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

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

相关文章

让大脑处于顶峰的14个保养技巧

让大脑处于顶峰的14个保养技巧 阅读。 之所以第一个写阅读,是因为阅读需要大脑将已认知的信息与新接触信息结合从而更容易激发人的想象力,而图片与视频虽然更直观,但理解和思考的过程却缩短了,大脑得到的锻炼也十分局限。阅读是让…

Typesript的type和interface的异同?

详解TypeScript中type与interface的区别_javascript技巧_脚本之家 一、相同的地方 1、都可以用来定义对象,描述函数 我们在用typescript开发的时候经常要用到数据类型定义,比如我们写一个接口或者函数的时候定义传参数据类型及字段等。这样子方便知道这…

opencascade AIS_PointCloud源码学习

AIS_PointCloud 前言 交互对象用于一组点。 表示支持两种显示模式: 点。 用于高亮显示的边界框。 表示通过边界框提供选择。 选择和高亮显示可以通过将默认选择模式设置为 -1 来禁用。 这样在交互视图中将无法选择对象。任何调用 AIS_InteractiveContext::AddOrRem…

Lua编程

文章目录 概述lua数据类型元表注意 闭包表现 实现 lua/c 接口编程skynet中调用层次虚拟栈C闭包注册表userdatalightuserdata 小结 概述 这次是skynet,需要一些lua/c相关的。写一篇博客,记录下。希望有所收获。 lua数据类型 boolean , number , string…

【一图学技术】2.API测试9种方法图解

9种API测试方法 冒烟测试:冒烟测试是一种快速的表面级测试,用于验证软件的基本功能是否正常工作,以确定是否值得进行更详细的测试。功能测试:功能测试是验证软件是否符合预期功能要求的测试类型。它涉及对每个功能进行测试&#…

[C++进阶]对于多态的底层逻辑

上回我们了解到了多态的定义,概念以及实现,对于多态如何使用和使用条件进行了了解,本篇我们将了解多态的原理。 一、虚函数表 首先我们看看如下代码&#xff1a; #include<iostream> using namespace std; class Base { public:virtual void Func1(){cout << &qu…

动手学深度学习V2每日笔记(权重衰退+Dropout)

本文主要参考沐神的视频教程 https://www.bilibili.com/video/BV1UK4y1o7dy/vd_sourcec7bfc6ce0ea0cbe43aa288ba2713e56d 文档教程 https://zh-v2.d2l.ai/ 本文的主要内容对沐神提供的代码中个人不太理解的内容进行笔记记录&#xff0c;内容不会特别严谨仅供参考。 1.函数目录…

百某应JS逆向

https://ying.baichuan-ai.com/ 目录 一、发起提问 二、观察发现有两个加密参数&#xff1a;X-Bc-Sig和X-Bc-Ts ​三、观察JS调用栈 四、从JS中搜索 X-Bc-Sig和X-Bc-Ts 五、断点并分析参数的生成方式 六、分析入参 七、发现关键的o方法调用了一个i()方法 八、验证结果 …

sqlilabs解题方法

Lass1 查询id为1的用户名和密码 查询id为2的用户名和密码 没有回显&#xff0c;不含id-1的行 判断字段数&#xff0c;字段数为3 查询数据库用户名&#xff0c;和数据库名 查询时id必须超出数据库以外&#xff0c;一般用-1 用户名&#xff1a;user() 数据库名&#xff1a;databa…

VulnHub:colddbox easy

靶机下载地址 信息收集 主机发现 攻击机网段192.168.31.0/24&#xff0c;扫描同网段存活主机。 nmap 192.168.31.0/24 -Pn -T4 发现靶机&#xff0c;IP为192.168.31.176。 端口扫描 扫描靶机开放端口。 nmap 192.168.31.176 -A -p- -T4 开放了80,4512端口&#xff0c;注…

[H并查集] lc100347. 判断矩形的两个角落是否可达(并查集+高质量+周赛408_4)

文章目录 1. 题目来源2. 题目解析 1. 题目来源 链接&#xff1a;100347. 判断矩形的两个角落是否可达 参考&#xff1a; 灵神视频题解&#xff1a;筛质数 巧妙枚举 并查集【力扣周赛 408】 这一期周赛很不错。 2. 题目解析 十分不错的题目哈&#xff0c;关键是题意的转换…

哈希 Hash(闭散列、开散列介绍及其实现)

目录 unordered 系列关联式容器unordered_mapunordered_map 的介绍unordered_map 的接口说明构造函数容量函数迭代器元素访问查询操作修改操作桶操作 unordered_setunordered_set 的介绍unordered_set 的接口说明构造函数容量函数迭代器查询操作修改操作桶操作 底层结构哈希概念…

Catalyst优化器:让你的Spark SQL查询提速10倍

目录 1 逻辑优化阶段 2.1 逻辑计划解析 2.2 逻辑计划优化 2.2.1 Catalys的优化过程 2.2.2 Cache Manager优化 2 物理优化阶段 2.1 优化 Spark Plan 2.1.1 Catalyst 的 Join 策略 2.1.2 如何决定选择哪一种 Join 策略 2.2 Physical Plan 2.2.1 EnsureRequirements 规则 3 相关文…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十七章 Linux中断实验

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

python 裁剪图片

情况&#xff1a; 有时候看视频&#xff0c;看到一个漂亮的妹子&#xff0c;按下 Alt PrintScreen 进行截图之后&#xff0c;会把整个屏幕都截图。 需要适当剪裁一下。 每次打开 PS &#xff0c; 也太慢了。 所以写个代码&#xff0c; 快速处理。 效果对比&#xff1a; 原始…

个人定制化形象生成,FaceChain最新模型部署

FaceChain是阿里巴巴达摩院推出的一个开源的人物写真和个人数字形象的AI生成框架。 FaceChain利用了Stable Diffusion模型的文生图功能&#xff0c;并结合人像风格化LoRA模型训练及人脸相关感知理解模型&#xff0c;将输入的图片进行训练后推理输出生成个人写真图像。 FaceCh…

【redis】对hash类型和list类型的常用命令,应用场景,内部编码的总结

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

初识c++:vector全方面讲解及其代码模拟实现

本节大纲&#xff1a; vector全方面讲解及其代码模拟实现 1.学习vector方法 2.vector的使用 2.1 vector的定义 2.2 vector iterator 的使用 2.3 vector 空间增长问题 2.4 vector 增删查改 2.5 vector 迭代器失效问题&#xff08;重点&#xff09; 3.vector 深度刨析 4…

【Vulnhub系列】Vulnhub_Raven2靶场渗透(原创)

【Vulnhub系列靶场】Vulnhub_Raven2 渗透 原文转载已经过授权 原文链接&#xff1a;Lusen的小窝 - 学无止尽&#xff0c;不进则退 (lusensec.github.io) 一、环境准备 从网盘下载该靶机&#xff0c;在vm中选择【打开】 然后设置好存储路径&#xff0c;开机后检查靶机的网络连…

主宰生物进化的 “魔咒” —— 制约生物在特殊环境下进化方式的线索

一些神秘的法则制约着生物在特殊环境下的进化方式。它们还为动物将如何适应气候变暖提供了线索。 一些奇特的进化现象 一艘装满大象和老鼠的 “诺亚方舟” 搁浅在一座偏远的小岛上。动物们都幸存下来并繁衍后代。但是&#xff0c;随着世代相传&#xff0c;奇怪的事情发生了&a…