dataStructure_图的应用DAG/AOV/拓扑排序/AOE/关键路径和关键活动
文章目录
DAG
- 有向无环图:GAG=directed acyclic graph
- acyclic/ˌeɪ’saɪklɪk/非周期的;非循环的;无环的
- 有向无环图是不存在顺时针环和逆时针环的图
- 描述含有公共子表达式的有效工具
AOV
-
Activity On Vertex (AOV) Network:
-
**a directed graph in which the vertices represent tasks or activities and **
-
the edges represent precedence relations between tasks.
-
有向边 < V i , V j > 表示活动 V i 必须在 V j 之前进行 有向边<V_i,V_j>表示活动V_i必须在V_j之前进行 有向边<Vi,Vj>表示活动Vi必须在Vj之前进行
-
AOV网中的活动具有传递性,
-
拓扑排序
- 对DAG的顶点进行的一种排序,使得,若存在A到B的路径,则在排序中,顶点B出现在A之后
- AOV网有一个或者多个拓扑序列序列
拓扑排序算法
- 遍历所有顶点的入度
- 将所有入度为0的顶点(没有前驱)压入栈中
- 输出这个被弹出的顶点,同时计数已经弹出的顶点个数
- 检查0度顶点栈,如果栈中非空,则弹出栈顶元素i
- 并且扫描出栈的顶点i指向的顶点(即顶点i的邻接顶点),将它们的入度减去1(撤掉被弹出元素相关的边)
- 这样可能得到新的入度为0的顶点,则把这样的顶点也压入栈中
- 检查拓扑排序是否成功(输出计数是否和图的顶点数一致)
- 如果不一致,说明被排序图是不是DAG,而是存在环路的
性能分析
- 如果图采用邻接表存储,那么时间复杂度为O(|V|+|E|)
- |V|是因为要遍历每个顶点(输出全部顶点)
- |E|是要访问0度点的邻接边,最终全图的所有边被访问一遍
- 如果是邻接矩阵,访问所有边的时间复杂度为 O ( ∣ V ∣ 2 ) O(|V|^2) O(∣V∣2)
逆拓扑排序
-
定义上形式和拓扑排序和相似,入度为0改为了出度为0
-
对一个AOV网采用如下步骤进行排序,则称为逆拓扑排序
- 从AOV网中选择一个没有后继的(出度为0)的顶点,并输出
- 从网中删除被输出的元素以及以该元素为终点的有向边
- 重复上述步骤知道AOV网为空
-
在求解AOE的事件发生最迟时间时,会用到逆拓扑排序
AOE
-
Activity On Edge(AOE) Network:
-
用边表示活动的网络
-
和AOV一样,都是DAG
-
AOE,AOV的顶点和边的含义不同
-
-
A O E 的顶点 : 表示事件 ( 信号 ) : 只有某顶点 V i 事件发生后 , V i 的各个出边活动 < V i , V j > 才能够开始 AOE的顶点:表示事件(信号):只有某顶点V_i事件发生后,V_i的各个出边活动<V_i,V_j>才能够开始 AOE的顶点:表示事件(信号):只有某顶点Vi事件发生后,Vi的各个出边活动<Vi,Vj>才能够开始
-
AOE的边:表示活动,且边的权值表示完成该活动的开销
- 只有 V i 的各个入边的活动结束后 , V i 的事件才可以开始 只有V_i的各个入边的活动结束后,V_i的事件才可以开始 只有Vi的各个入边的活动结束后,Vi的事件才可以开始
关键路径
-
具有最大路径长度的路径称为
关键路径
- 完成整个工程所需要的最短时间就是关键路径的长度
-
关键路径上的活动称为关键活动
AOE时间点相关概念和问题
- 教材的紧凑的描述语言
事件 v k 的最早发生时间 v e ( k ) 事件v_k的最早发生时间ve(k) 事件vk的最早发生时间ve(k)
-
ve=VertexEarliest
-
它是指,从原点v1到顶点vk的最长路径长度
- 事件 v k 的最早发生时间决定了所有从 v k 开始的活动能够开工的最早时间 事件v_k的最早发生时间决定了所有从v_k开始的活动能够开工的最早时间 事件vk的最早发生时间决定了所有从vk开始的活动能够开工的最早时间
-
它可以用一个递推公式来计算
-
v e ( v 1 ) = 0 , v 1 表示源点 , v n 表示汇点 ( 在 A O E 中 , 都是唯一的 ) ve(v_1)=0,v_1表示源点,v_n表示汇点(在AOE中,都是唯一的) ve(v1)=0,v1表示源点,vn表示汇点(在AOE中,都是唯一的)
-
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 ∈ P r e d e c e s s o r ( v k ) , P r e d e c e s s o r ( v k ) 是 v k 的前驱集合 v_j\in Predecessor(v_k),Predecessor(v_k)是v_k的前驱集合 vj∈Predecessor(vk),Predecessor(vk)是vk的前驱集合
-
事件 v k 的最迟发生时间 v l ( k ) 事件v_k的最迟发生时间vl(k) 事件vk的最迟发生时间vl(k)
-
vl:VertexLatest
-
类似的,也可以用递推公式来计算
-
v l ( v n ) = v e ( v n ) vl(v_n)=ve(v_n) vl(vn)=ve(vn)//可见,计算事件最晚发生vl依赖于事件最早发生时间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 ∈ S u c c e s s o r ( v k ) , S u c c e s s o r ( v k ) 是 v k 的后继的集合 其中,v_j\in Successor(v_k),Successor(v_k)是v_k的后继的集合 其中,vj∈Successor(vk),Successor(vk)是vk的后继的集合
-
总的一个思路就是 , v j 前驱结点 v k 上的事件发生及其出边 < v k , v j > 的活动总时长 不能够影响到后继结点 v j 在死线时间 ( v l ( j ) 之前必须完成的要求 ) 更好的说法是作为前驱的结点 v k 必须在其所有后继的最迟发生时间 v l ( j ) 之前就要完成 以此来计算 v l ( k ) 的值 也就是 v l ( k ) = M i n ( v l ( j ) − W e i g h t ( v k , v j ) ) 总的一个思路就是,v_j前驱结点v_k上的事件发生及其出边<v_k,v_j>的活动总时长 \\不能够影响到后继结点v_j在死线时间(vl(j)之前必须完成的要求) \\更好的说法是作为前驱的结点v_k必须在其所有后继的最迟发生时间vl(j)之前就要完成 \\以此来计算vl(k)的值 \\也就是vl(k)=Min(vl(j)-Weight(v_k,v_j)) 总的一个思路就是,vj前驱结点vk上的事件发生及其出边<vk,vj>的活动总时长不能够影响到后继结点vj在死线时间(vl(j)之前必须完成的要求)更好的说法是作为前驱的结点vk必须在其所有后继的最迟发生时间vl(j)之前就要完成以此来计算vl(k)的值也就是vl(k)=Min(vl(j)−Weight(vk,vj))
弧的相关时间结点
- 有了前面两个概念的铺垫,我们可以比较容易的导出:活动弧的最早开始时间和最晚开始时间
- 记弧 i = < p i , s i > , 对应于 < 弧尾 , 弧头 > 记弧i=<p_i,s_i>,对应于<弧尾,弧头> 记弧i=<pi,si>,对应于<弧尾,弧头>
弧的最早开始时间
-
e=Earliest
-
e ( i ) = v e ( p i ) e(i)=ve(p_i) e(i)=ve(pi)
弧的最晚开始时间
- l = L a s t e s t l=Lastest l=Lastest
- l ( i ) = v l ( s i ) − w ( i ) ; 其中弧 i 的活动持续的时间 w ( i ) = w e i g h t ( p i , s i ) l(i)=vl(s_i)-w(i);其中弧i的活动持续的时间w(i)=weight(p_i,s_i) l(i)=vl(si)−w(i);其中弧i的活动持续的时间w(i)=weight(pi,si)
- 注意,有的弧开始时间可以早或晚一些,但是活动完成需要的时间长度是不变的
关键活动
-
满足e(i)=l(i)的弧(活动)就是关键活动
- 无法提前开始,也无法推迟开始
-
关键路径上的活动(弧)都是关键活动
-
网络中的关键有时不唯一,对于存在多条关键路径的网,只有加快被所有关键路径都包括了的关键活动才能够达到缩短工期的目的
- 因此,加快关键活动的完成只是缩短工期的必要条件,不是充分条件(不保证能够缩短工期)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了