6.6 拓扑排序与关键路径

有向无环图与表达式,AOV 网的拓扑排序,AOE 网中事件与活动的时间计算及关键路径。

考查要求 ★★★ 重点掌握 DAG 表示表达式拓扑排序逆拓扑排序ve 与 vl关键活动关键路径

有向无环图描述表达式

若一个有向图中不存在环,则称为有向无环图,简称 DAG。

有向无环图是描述含有公共子式的表达式的有效工具。例如表达式 ((a+b)×(b×(c+d))+(c+d)×e)×((c+d)×e)((a+b) \times (b \times (c+d)) + (c+d) \times e) \times ((c+d) \times e),若用二叉树表示,则其中的相同子式 (c+d)(c+d) 和 (c+d)×e(c+d) \times e 会重复出现;若利用有向无环图,则可实现对相同子式的共享,从而节省存储空间。

拓扑排序

AOV 网:若用 DAG 表示一个工程,其顶点表示活动,用有向边 ⟨Vi,Vj⟩\langle V_i, V_j \rangle 表示活动 ViV_i 必须先于活动 VjV_j 进行的这样一种关系,则将这种有向图称为顶点表示活动的网络,记为 AOV 网。在 AOV 网中,活动 ViV_i 是活动 VjV_j 的直接前驱,活动 VjV_j 是活动 ViV_i 的直接后继,这种前驱和后继关系具有传递性,且任何活动 ViV_i 不能以它自己作为自己的前驱或后继。

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

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

对一个 AOV 网进行拓扑排序的算法有很多,下面介绍比较常用的一种方法的步骤:

  1. 从 AOV 网中选择一个没有前驱(入度为 0)的顶点并输出;
  2. 从网中删除该顶点和所有以它为起点的有向边;
  3. 重复 1 和 2 直到当前的 AOV 网为空或当前网中不存在无前驱的顶点为止。后一种情况说明有向图中必然存在环。
动画演示拓扑排序
1入度 02入度 13入度 14入度 25入度 26入度 1栈 S(栈底 → 栈顶)拓扑序列
输出的顶点在栈中(入度为 0)入度被修改已删除
C 代码
1bool TopologicalSort(Graph G) {
2 InitStack(S);
3 for (int i = 0; i < G.vexnum; i++)
4 if (indegree[i] == 0)
5 Push(S, i); // 所有入度为 0 的顶点入栈
6 int count = 0;
7 while (!IsEmpty(S)) {
8 Pop(S, i);
9 print[count++] = i; // 输出顶点 i
10 for (p = G.vertices[i].firstarc; p; p = p->nextarc) {
11 v = p->adjvex; // 将 i 指向的顶点入度减 1
12 if (!(--indegree[v]))
13 Push(S, v); // 入度为 0 则入栈
14 }
15 }
16 return count == G.vexnum; // count < n 说明有回路
17}
1/16统计各顶点的入度,把所有入度为 0 的顶点压入栈

逆拓扑排序:每次输出出度为 0 的顶点,删除它和所有以它为终点的有向边。利用 DFS 也能实现逆拓扑排序——在顶点退出递归时输出。

关键路径

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

AOE 网具有以下两个性质:

  1. 只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始;
  2. 只有在进入某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发生。

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

从源点到汇点的所有路径中,具有最大路径长度的路径称为关键路径,而把关键路径上的活动称为关键活动。完成整个工程的最短时间就是关键路径的长度,即关键路径上各活动花费开销的总和。

五个量

量含义计算方法
ve(k)ve(k)事件 vkv_k 的最早发生时间从源点开始按拓扑序:ve(源点)=0ve(\text{源点}) = 0,ve(k)=max⁡{ve(j)+Weight(vj,vk)}ve(k) = \max\{ve(j) + \mathrm{Weight}(v_j, v_k)\}
vl(k)vl(k)事件 vkv_k 的最迟发生时间从汇点开始按逆拓扑序:vl(汇点)=ve(汇点)vl(\text{汇点}) = ve(\text{汇点}),vl(k)=min⁡{vl(j)−Weight(vk,vj)}vl(k) = \min\{vl(j) - \mathrm{Weight}(v_k, v_j)\}
e(i)e(i)活动 ai=⟨vk,vj⟩a_i = \langle v_k, v_j \rangle 的最早开始时间e(i)=ve(k)e(i) = ve(k)
l(i)l(i)活动 aia_i 的最迟开始时间l(i)=vl(j)−Weight(vk,vj)l(i) = vl(j) - \mathrm{Weight}(v_k, v_j)
d(i)d(i)活动的时间余量d(i)=l(i)−e(i)d(i) = l(i) - e(i),d(i)=0d(i) = 0 的活动是关键活动
动画演示关键路径
a1=3a2=2a3=2a4=3a5=4a6=3a7=2a8=1V1ve=? vl=?V2ve=? vl=?V3ve=? vl=?V4ve=? vl=?V5ve=? vl=?V6ve=? vl=?活动elda1<v1,v2>a2<v1,v3>a3<v2,v4>a4<v2,v5>a5<v3,v4>a6<v3,v6>a7<v4,v6>a8<v5,v6>
正在计算的事件参与计算的前驱/后继关键活动
计算公式
1// ① 按拓扑序求事件最早发生时间 ve
2ve(源点) = 0;
3ve(k) = max{ ve(j) + Weight(vj, vk) } // vj 为 vk 的任意前驱
4// ② 按逆拓扑序求事件最迟发生时间 vl
5vl(汇点) = ve(汇点);
6vl(k) = min{ vl(j) - Weight(vk, vj) } // vj 为 vk 的任意后继
7// ③ 活动 ai = <vk, vj> 的最早开始时间 e 与最迟开始时间 l
8e(i) = ve(k);
9l(i) = vl(j) - Weight(vk, vj);
10// ④ d(i) = l(i) - e(i),d(i) == 0 的活动为关键活动
1/16AOE 网:顶点表示事件,有向边表示活动,边权表示活动持续时间。先按拓扑序求各事件的最早发生时间 ve

本例的关键路径为 V1→V3→V4→V6V_1 \to V_3 \to V_4 \to V_6,关键活动为 a2,a5,a7a_2, a_5, a_7,工程最短完成时间为 8。

即时练习

即时练习4 题
点击选项即可作答
  1. 1
    若用邻接矩阵存储有向图,矩阵中主对角线以下的元素均为零,则关于该图拓扑序列的结论是( )。
  2. 2
    下列关于 AOE 网的叙述中,不正确的是( )。
  3. 3
    对本课的 AOV 网示例进行拓扑排序(每次可任选一个入度为 0 的顶点),下列序列中不是其拓扑序列的是( )。
  4. 4
    在本课的 AOE 网示例中,活动 a₃ = ⟨V₂, V₄⟩(权值 2)的时间余量 d 为( )。
学完了吗?

标记完成后,侧栏会显示进度。进度仅保存在本浏览器中。