【数据结构与算法】拓扑排序与关键路径

news2024/9/21 18:00:24

🔥 本文由 程序喵正在路上 原创,CSDN首发!
💖 系列专栏:数据结构与算法
🌠 首发时间:2022年12月4日
🦋 欢迎关注🖱点赞👍收藏🌟留言🐾
🌟 一以贯之的努力 不得懈怠的人生

阅读指南

  • 有向无环图描述表达式
    • 有向无环图(DAG)
    • DAG 描述表达式
    • 解题方法
  • 拓扑排序
    • AOV网
    • 拓扑排序
    • 逆拓扑排序
    • 逆拓扑排序的实现(DFS算法)
  • 关键路径
    • AOE网
    • 求关键路径的步骤
    • 关键活动、关键路径的特性

有向无环图描述表达式

有向无环图(DAG)

如果一个有向图中不存在环,则称之为有向无环图,简称 D A G DAG DAG 图( D i r e c t e d   A c y c l i c   G r a p h Directed \ Acyclic \ Graph Directed Acyclic Graph),比如下面这个图

在这里插入图片描述

DAG 描述表达式

有下面这样一个表达式:

( ( a + b ) ∗ ( b ∗ ( c + d ) ) + ( c + d ) ∗ e ) ∗ ( ( c + d ) ∗ e ) ((a + b) * (b * (c + d)) + (c + d) * e) * ((c + d) * e) ((a+b)(b(c+d))+(c+d)e)((c+d)e)

我们可以将其表示成树的形式:

在这里插入图片描述

但是我们会发现,树中有些地方是重复的,比如 ( c + d ) ∗ e (c + d) * e (c+d)e 这部分,所以我们删除一部分,变成

在这里插入图片描述

接着我们发现还有 c + d c + d c+d 这部分也重复了,也得删去

在这里插入图片描述

最后还有 b b b 也重复

在这里插入图片描述

规律:顶点中不可能出现重复的操作数

解题方法

  1. 把各个操作数不重复地排成一排
    在这里插入图片描述

  2. 标出每个运算符的生效顺序(先后顺序有点出入无所谓)
    在这里插入图片描述

  3. 按顺序加入运算符,注意 “分层”
    在这里插入图片描述

  4. 从底向上逐层检查同层的运算符是否可以合体
    在这里插入图片描述

拓扑排序

AOV网

A O V AOV AOV 网( A c t i v i t y   O n   V e r t e x   N e t W o r k Activity \ On \ Vertex \ NetWork Activity On Vertex NetWork,用顶点表示活动的网):用 D A G DAG DAG 图(有向无环图)表示一个工程。顶点表示活动,有向边 < V i , V j > <V_i, V_j> <Vi,Vj> 表示活动 V i V_i Vi 必须先于活动 V j V_j Vj 进行

拓扑排序

在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序:

  • 每个顶点出现且只出现一次
  • 若顶点 A A A 在序列中排在顶点 B B B 的前面,则在图中不存在从顶点 B B B 到顶点 A A A 的路径

每个 A O V AOV AOV 网都有一个或多个拓扑排序序列

拓扑排序的实现:

  1. A O V AOV AOV 网中选择一个没有前驱(入度为 0 0 0)的顶点并输出
  2. 从网中删除该顶点和所有以它为起点的有向边
  3. 重复 1 1 1 2 2 2 直到当前的 A O V AOV AOV 网为空或者当前网中不存在无前驱的顶点为止
#define MaxVertexNum 100				//图中顶点数目的最大值
typedef struct ArcNode {				//边表结点
	int adjvex;							//该弧所指向的顶点的位置
	struct ArcNode *nextarc;			//指向下一条弧的指针
	//InfoType info;					//网的边权值
}ArcNode;

typedef struct VNode {					//顶点表结点
	VertexType data;					//顶点信息
	ArcNode *firstarc;					//指向第一条依附该顶点的弧的指针
}VNode, AdjList[MaxVertexNum];

typedef struct {
	AdjList vertices;					//邻接表
	int vexnum, arcnum;					//图的顶点数和弧数
}Graph;									//Graph是以邻接表存储的图类型

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)) {		//栈不空,则存在入度为0的顶点
		Pop(S, i);				//栈顶元素出栈
		print[count++] = i;		//输出顶点i
		
		for (p = G.vertices[i].firstarc; p; p = p->nextarc) {
			//将所有i指向的顶点的入度减1,并且将入度减为0的顶点压入栈S
			v = p->adjvex;
			if (!(--indegree[v])) Push(S, v);	//入度为0,则入栈
		}//for
	}//while

	if (count < G.vexnum) return false;		//排序失败,有向图中有回路
	else return true;						//拓扑排序成功

其中 indegree 是记录各个顶点入度的数组,初始化为各顶点的入度;print 是记录拓扑序列的数组,初始化为 − 1 -1 1

在这个拓扑排序中,每个顶点和每条边都需要处理一次,整体的时间复杂度为 O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|) O(V+E),如果是采用邻接矩阵存储的图,则需要 O ( ∣ V ∣ 2 ) O(|V|^2) O(V2) 的时间复杂度

逆拓扑排序

逆拓扑排序的实现:

  1. A O V AOV AOV 网中选择一个没有后继(出度为 0 0 0)的顶点并输出
  2. 从网中删除该顶点和所有以它为终点的有向边
  3. 重复 1 1 1 2 2 2 直到当前的 A O V AOV AOV 网为空

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

void DFSTraverse(Graph G) {				//对图G进行深度优先遍历
	for (v = 0; v < G.vexnum; ++v) 		//初始化已访问标记数据
		visited[v] = false;
		
	for (v = 0; v < G.vexnum; ++v)
		if (!visited[v]) DFS(G, v);
}

void DFS(Graph G, int v) {				//从顶点v开始,深度优先遍历图G
	visited[v] = true;					//设置已访问标记
	for (w = FirstNeighbor(G, v); w >= 0; w = NextNeighbor(G, v, w))
		if (!visited[w]) DFS(G, w);
	
	print(v);			//输出顶点
}

如果图中存在回路,那么上面的程序就不再使用,我们需要给每个顶点添加一个是否已经入栈的标记来判断是否有回路即可

关键路径

AOE网

在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销(如完成该活动所需的时间),称之为哟个边表示活动的网络,简称 A O E AOE AOE 网( A c t i v i t y   O n   E d g e   N e t W o r k Activity \ On \ Edge \ NetWork Activity On Edge NetWork

在这里插入图片描述

A O E AOE AOE 网具有以下两个性质:

  • 只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始
  • 只有在进入某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发生。另外,有些活动是可以并行进行的

A O E AOE AOE 网中仅有一个入度为 0 0 0 的顶点,称为开始顶点(源点),它表示整个工程的开始;也仅有一个出度为 0 0 0 的顶点,称为结束顶点(汇点),它表示整个工程的结束

从源点到汇点的有向路径可能有多条,所有路径中,具有最大路径长度的路径称为关键路径,而把关键路径上的活动称为关键活动

完成整个工程的最短时间就是关键路径的长度,若关键活动不能按时完成,则整个工程的完成时间就会延长

事件 v k v_k vk 的最早开始时间 v e ( k ) ve(k) ve(k) —— 决定了所有从 v k v_k vk 开始的活动能够开工的最早时间

活动 a i a_i ai 的最早开始时间 e ( i ) e(i) e(i) —— 指该活动弧的起点所表示的事件的最早发生时间

事件 v k v_k vk 的最迟开始时间 v l ( k ) vl(k) vl(k) —— 它是指在不推迟整个工程完成的前提下,该事件最迟应该发生的时间

活动 a i a_i ai 的最迟开始时间 l ( i ) l(i) l(i) —— 它是指该活动弧的终点所表示事件的最迟发生时间与该活动所需时间之差

活动 a i a_i ai 的时间余量 d ( i ) = l ( i ) − e ( i ) d(i) = l(i) - e(i) d(i)=l(i)e(i),表示在不增加完成整个工程所需总时间的情况下,活动 a i a_i ai 可以拖延的时间;若一个活动的时间余量为零,则说明该活动必须要如期完成, d ( i ) = 0 d(i) = 0 d(i)=0 l ( i ) = e ( i ) l(i) = e(i) l(i)=e(i) 的活动是关键活动,由关键活动组成的路径就是关键路径

求关键路径的步骤

  1. 求所有事件的最早发生时间 v e ( ) ve() ve()
  2. 求所有事件的最迟发生时间 v l ( ) vl() vl()
  3. 求所有活动的最早发生时间 e ( ) e() e()
  4. 求所有活动的最迟发生时间 l ( ) l() l()
  5. 求所有活动的时间余量 d ( ) d() d()

在这里插入图片描述

① 求所有事件的最早发生时间 v e ( ) ve() ve()

按拓扑排序序列,依次求各个顶点的 v e ( k ) ve(k) ve(k)

  • v e ve ve( 源点 ) = 0 = 0 =0
  • v e ( k ) = M a x { v e ( j ) + W e i g h t ( v j , v k ) } ve(k) = Max\{ve(j) + Weight(v_j, v_k)\} ve(k)=Max{ve(j)+Weight(vj,vk)} v j v_j vj v k v_k vk 的任意前驱

上图的拓扑序列为: V 1 、 V 3 、 V 2 、 V 5 、 V 4 、 V 6 V_1、V_3、V_2、V_5、V_4、V_6 V1V3V2V5V4V6

那么

v e ( 1 ) = 0 ve(1) = 0 ve(1)=0

v e ( 3 ) = 2 ve(3) = 2 ve(3)=2

v e ( 2 ) = 3 ve(2) = 3 ve(2)=3

v e ( 5 ) = 6 ve(5) = 6 ve(5)=6

v e ( 4 ) = m a x { v e ( 2 ) + 2 , v e ( 3 ) + 4 } = 6 ve(4) = max\{ve(2) + 2, ve(3) + 4\} = 6 ve(4)=max{ve(2)+2,ve(3)+4}=6

v e ( 6 ) = m a x { v e ( 5 ) + 1 , v e ( 4 ) + 2 , v e ( 3 ) + 3 } = 8 ve(6) = max\{ve(5) + 1, ve(4) + 2, ve(3) + 3\} = 8 ve(6)=max{ve(5)+1,ve(4)+2,ve(3)+3}=8

② 求所有事件的最迟发生时间 v l ( ) vl() vl()

按逆拓扑排序序列,依次求各个顶点的 v l ( k ) vl(k) vl(k)

  • v l vl vl(汇点) = = = v e ve ve(汇点)
  • v l ( k ) = M i n { v l ( j ) + W e i g h t ( v k , v j ) } vl(k) = Min\{vl(j) + Weight(v_k, v_j)\} vl(k)=Min{vl(j)+Weight(vk,vj)} v j v_j vj v k v_k vk 的任意后继

上图的逆拓扑序列为: V 6 、 V 5 、 V 4 、 V 2 、 V 3 、 V 1 V_6、V_5、V_4、V_2、V_3、V_1 V6V5V4V2V3V1

那么

v l ( 6 ) = 8 vl(6) = 8 vl(6)=8

v l ( 5 ) = 7 vl(5) = 7 vl(5)=7

v l ( 4 ) = 6 vl(4) = 6 vl(4)=6

v l ( 2 ) = m i n { v l ( 5 ) − 3 , v l ( 4 ) − 2 } = 4 vl(2) = min\{vl(5) - 3, vl(4) - 2\} = 4 vl(2)=min{vl(5)3,vl(4)2}=4

v l ( 3 ) = m i n { v l ( 4 ) − 4 , v l ( 6 ) − 3 } = 2 vl(3) = min\{vl(4) - 4, vl(6) - 3\} = 2 vl(3)=min{vl(4)4,vl(6)3}=2

v l ( 1 ) = m i n { v l ( 2 ) − 3 , v l ( 3 ) − 2 } = 0 vl(1) = min\{vl(2) - 3, vl(3) - 2\} = 0 vl(1)=min{vl(2)3,vl(3)2}=0

③ 求所有活动的最早发生时间 e ( ) e() e()

若边 < v k , v j > <v_k, v_j> <vk,vj> 表示活动 a i a_i ai,则有 e ( i ) = v e ( k ) e(i) = ve(k) e(i)=ve(k),说白了就等于活动 a i a_i ai 所在弧的弧尾的事件的最早发生时间 v e ( k ) ve(k) ve(k),所以

e ( 1 ) = v e ( 1 ) = 0 ,   e ( 2 ) = v e ( 1 ) = 0 ,   e ( 3 ) = v e ( 2 ) = 3 ,   e ( 4 ) = 4 ,   e ( 5 ) = v e ( 3 ) = 2 ,   e ( 6 ) = 2 ,   e ( 7 ) = 6 ,   e ( 8 ) = 6 e(1) = ve(1) = 0, \ e(2) = ve(1) = 0, \ e(3) = ve(2) = 3, \ e(4) = 4, \ e(5) = ve(3) = 2, \ e(6) = 2, \ e(7) = 6, \ e(8) = 6 e(1)=ve(1)=0, e(2)=ve(1)=0, e(3)=ve(2)=3, e(4)=4, e(5)=ve(3)=2, e(6)=2, e(7)=6, e(8)=6

④ 求所有活动的最迟发生时间 l ( ) l() l()

若边 < v k , v j > <v_k, v_j> <vk,vj> 表示活动 a i a_i ai,则有 l ( i ) = v l ( j ) − W e i g h t ( v k , v j ) l(i) = vl(j) - Weight(v_k, v_j) l(i)=vl(j)Weight(vk,vj),所以

l ( 1 ) = v l ( 2 ) − 3 = 1 ,   l ( 2 ) = v l ( 3 ) − 2 = 0 ,   l ( 3 ) = 4 ,   l ( 4 ) = 4 ,   l ( 5 ) = 2 ,   l ( 6 ) = 5 ,   l ( 7 ) = 6 ,   l ( 8 ) = 7 l(1) = vl(2) - 3 = 1, \ l(2) = vl(3) - 2 = 0, \ l(3) = 4, \ l(4) = 4, \ l(5) = 2, \ l(6) = 5, \ l(7) = 6, \ l(8) = 7 l(1)=vl(2)3=1, l(2)=vl(3)2=0, l(3)=4, l(4)=4, l(5)=2, l(6)=5, l(7)=6, l(8)=7

⑤ 求所有活动的时间余量 d ( ) d() d()

d ( i ) = l ( i ) − e ( i ) d(i) = l(i) - e(i) d(i)=l(i)e(i)

方面 a 1 a_1 a1 a 2 a_2 a2 a 3 a_3 a3 a 4 a_4 a4 a 5 a_5 a5 a 6 a_6 a6 a 7 a_7 a7 a 8 a_8 a8
e ( k ) e(k) e(k)00332266
l ( k ) l(k) l(k)10442567
d ( k ) d(k) d(k)10110301

关键活动: a 2 、 a 5 、 a 7 a_2、a_5、a_7 a2a5a7

关键路径: V 1 − > V 3 − > V 4 − > V 6 V_1 -> V_3 -> V_4 -> V_6 V1>V3>V4>V6

关键活动、关键路径的特性

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

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

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

相关文章

【C++智能指针】智能指针的发展和循环引用的原理和解决

目录 1.RAIl&#xff08;智能指针的雏形&#xff09; 2.拷贝导致的问题以及智能指针发展历史 2.1拷贝的问题&#xff08;资源被析构两次&#xff09; 2.2auto_ptr(资源权转移&#xff0c;不建议使用) 2.3unique_ptr(防拷贝&#xff0c;在不需要拷贝的情况下使用) 2.4share…

【vue】vue-count-to(数字滚动)插件:

文章目录一、效果&#xff1a;二、使用&#xff1a;【1】安装插件【2】案例三、Options四、Functions一、效果&#xff1a; 二、使用&#xff1a; 官方文档&#xff1a; github地址——https://github.com/PanJiaChen/vue-countTo npm地址——https://www.npmjs.com/package/…

在本地PC运行 Stable Diffusion 2.0

Stable Diffusion 2.0在前几天已经发布了&#xff0c;新版本在上一个版本的基础上进行了许多改进。OpenCLIP中新的深度检测和更好的文本到图像模型是主要的改进之一。 有很多的文章介绍了Stable Diffusion 2.0的改进&#xff0c;所以我们就不多介绍了&#xff0c;这里我们将介…

30分钟部署一个kubernetes集群【1.17】

作者:李振良 kubeadm是官方社区推出的一个用于快速部署kubernetes集群的工具。 这个工具能通过两条指令完成一个kubernetes集群的部署: # 创建一个 Master 节点 $ kubeadm init# 将一个 Node 节点加入到当前集群中 $ kubeadm join <Master节点的IP和端口 >1. 安装要求…

.m3u8.sqlite文件转mp4,m3u8.sqlite文件转视频工具(开源免费)

文章目录一、预先准备1. 前提2. 主要思路3. 准备工具二、视频转换实战2.1. 软件下载2.2. TS转MP4工具2.3. 操作流程一、预先准备 1. 前提 如果已经买了课程&#xff0c;是可以下载的&#xff0c;并且腾讯课堂APP里就有下载功能。 2. 主要思路 在APP上下载视频缓存到手机本地…

postgres源码解析41 btree索引文件的创建--1

上述小节讲解了索引文件的物理创建&#xff0c;本篇讲解btree索引元组填充至索引文件的操作。先从数据结构入手&#xff0c;后深入执行流程。 postgres源码解析37 表创建执行全流程梳理–1 postgres源码解析37 表创建执行全流程梳理–2 postgres源码解析37 表创建执行全流程梳理…

详解设计模式:责任链模式

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;也被称为职责链模式&#xff0c;是在 GoF 23 种设计模式中定义了的行为型模式。 责任链模式 是将链中的每一个节点看作是一个对象&#xff0c;每个节点处理的请求不同&#xff0c;且内部自动维护一个下一节点…

降温了好冷,总结下11月

1、这两天广东气温骤降&#xff0c;出门必须加外套了&#xff0c;emmm&#xff0c;不想出门&#xff0c;各位宝宝注意保暖吖&#xff0c;别感冒了。2、这边疫情开始放开了&#xff0c;备好感冒药&#xff0c;锻炼身体&#xff0c;做好预防&#xff0c;靠自己了。3、11月过的真快…

jsp人事考勤管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 人事考勤管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统采用serlvetdaobean mvc 模式&#xff0c;系统主要采用B/S模式 开发。开发环境为TOMCAT7.0,Myeclipse8.…

[附源码]计算机毕业设计基于Springboot的花店售卖系统的设计与实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【45-线程的实现方式-线程池的创建方式-线程池的执行顺序-CompletableFutrue异步处理】

一.知识回顾 【0.三高商城系统的专题专栏都帮你整理好了&#xff0c;请点击这里&#xff01;】 【1-系统架构演进过程】 【2-微服务系统架构需求】 【3-高性能、高并发、高可用的三高商城系统项目介绍】 【4-Linux云服务器上安装Docker】 【5-Docker安装部署MySQL和Redis服务】…

物联网毕设 -- 基于STM32的心率检测

目录 前言 1 演示视频 一 连线图 1. 原理图 2.功能概括 二 底层代码使用方式 1. 下载程序 2. 查看云平台数据 三 APP使用方式 1. 下载APP 2. 配对蓝牙 四 网盘链接 前言 分享一个之前做到心率监测项目&#xff0c;有APP端有OLED显示端&#xff0c;我会把把他放…

Windows搭建web站点:免费内网穿透发布至公网 1-2

什么是cpolar&#xff1f; cpolar是一个非常强大的内网穿透工具&#xff0c;开发调试的必备利器。 它可以将本地内网服务器的HTTP、HTTPS、TCP协议端口映射为公网地址端口&#xff0c;使得公网用户可以轻松访问您的内网服务器&#xff0c;无需部署至公网服务器。支持永久免费使…

[附源码]Python计算机毕业设计Django软考刷题小程序

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

ssm项目整合,简单的用户管理系统

ssm项目整合&#xff0c;简单的用户管理系统项目概述项目搭建创建项目1.创建maven项目2.导入项目依赖及maven资源过滤设置3.添加web支持4.配置tomcat5.配置web发布依赖jar包6.数据库的表创建7.实体类创建7.1 lombok常用注解:dao层1.daoMapper接口创建2.Mapper.xml配置文件3.myb…

物联网iot全称

物联网iot的发展 麻省理工学院Ashton教授1999年研究RFID时最早提出物联网(Internet of Things&#xff0c; IoT)这个概念。Sun公司在2003年发表文章介绍物联网的基本工作流程&#xff0c;并提出解决方案。 IoT的意思是物联网&#xff0c;全称为Internet of Things。是指通过射…

狂神说Spring学习笔记

一、Spring 1.1 简介 Spring&#xff1a;春天------>给软件行业带来了春天&#xff01;2002&#xff0c;首次推出了Spring框架的雏形&#xff1a;interface21框架&#xff01;Spring框架即以interface21框架为基础&#xff0c;经过重新设计&#xff0c;并不断丰富其内涵&a…

metaRTC新增SRS的WebRTC over TCP和turn的TCP支持

概述 在很多网络条件下&#xff0c;防火墙会阻止UDP传输&#xff0c;因此webRTC TCP的支持就很重要&#xff0c;metaRTC提供了SFU和P2P的支持。 SFU支持SRS的webRTC over TCP&#xff0c;P2P支持turn的TCP。 源代码下载 GitHub - metartc/metaRTC: A cross-platform WebRTC…

[附源码]计算机毕业设计基于SpringBoot的小说阅读系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

8.softmax回归

1. 关于回归和多类分类 分类问题从回归的单输出变成了多输出&#xff0c;这个多输出的个数类别的个数 置信度&#xff1a;置信度一词来自统计学&#xff0c;而统计学的本质是&#xff0c;用抽样的数据去估计整体的真实分布。例如&#xff0c;样本均值估计整体均值&#xff1b;还…