拓扑排序与关键路径是图论中用于有向无环图(DAG)和AOE网(Activity On Edge Network)的重要算法,常用于项目调度与工期优化分析。
-
AOE网:是一种带权有向无环图,其中:
- 顶点表示事件(Event),即状态或里程碑;
- 有向边表示活动(Activity),边上的权值表示该活动所需持续时间;
- 源点(入度为0)表示工程开始,汇点(出度为0)表示工程结束。
-
拓扑排序:用于检测AOE网是否有环(若无法拓扑排序,则存在环,不能进行关键路径分析),并为后续计算提供顶点处理顺序(按事件发生的逻辑先后)。
-
最早开始时间(ve):从源点出发,沿所有路径到达某事件的最长路径长度(即该事件最早可能发生的时刻)。通过正向拓扑序动态规划计算:
ve[j] = max{ ve[i] + weight(i→j) },对所有前驱i。 -
最晚开始时间(vl):在保证工程总工期不变的前提下,该事件最迟必须发生的时刻。通过逆向拓扑序(从汇点反推)计算:
vl[i] = min{ vl[j] − weight(i→j) },对所有后继j。 -
关键路径:由所有满足
ve[i] == vl[i]的事件(顶点)所构成的、从源点到汇点的路径;其上所有活动(边)的最早开始时间 = 最晚开始时间(即e = l),这些活动称为关键活动,无机动时间,延迟将导致整个工期延长。
“32次”可能指某次练习/考试中该知识点共出现32题,或某算法执行中涉及32次关键操作(如32条边参与松弛/更新),需结合上下文确认;但核心仍围绕AOE建模、拓扑排序验证、ve/vl双遍历及关键路径提取。
# 简化版AOE关键路径计算示意(需先完成拓扑排序)
def critical_path(graph, n, source, sink):
# graph: 邻接表,graph[u] = [(v, w), ...]
ve = [-float('inf')] * n; ve[source] = 0
vl = [float('inf')] * n; vl[sink] = ve[sink] # 总工期 = ve[sink]
# 正向拓扑序更新ve(需提前获得拓扑序列topo_order)
for u in topo_order:
for v, w in graph[u]:
if ve[v] < ve[u] + w:
ve[v] = ve[u] + w
# 逆向拓扑序更新vl
for u in reversed(topo_order):
for v, w in graph[u]:
if vl[u] > vl[v] - w:
vl[u] = vl[v] - w
# 找关键活动:边u→v满足 ve[u] == vl[u] and ve[v] == vl[v] and ve[u] + w == ve[v]
critical_edges = []
for u in range(n):
for v, w in graph[u]:
if ve[u] == vl[u] and ve[v] == vl[v] and ve[u] + w == ve[v]:
critical_edges.append((u, v, w))
return critical_edges
判断一个AOE网中是否存在多条关键路径,核心在于:从源点到汇点是否存在两条或以上互不重合(或部分重合但整体不同)的最长路径(即总权值等于工程最短完成时间的路径)。关键路径本质是AOE网中源点到汇点的最长路径(因工期由最长路径决定),因此多条关键路径 ⇔ 存在多条长度均等于最大路径长度(即 ve[汇点])的不同有向路径。
✅ 判断方法:
- 先求出总工期 T = ve[汇点](即源点到汇点的最长路径长度);
- 从源点出发,用DFS/BFS或动态规划统计:从源点到汇点、路径长度恰好为 T 的不同路径条数;
- 可定义
dp[v]表示从源点到顶点 v 的长度为ve[v]的路径条数; - 初始化
dp[source] = 1; - 按拓扑序遍历,对每条边
u → v权值w,若ve[u] + w == ve[v],则dp[v] += dp[u];
- 可定义
- 若
dp[sink] ≥ 2,则存在多条关键路径。
⚠️ 注意:路径“不同”指顶点序列不同(即使共享部分边,只要整体路径不完全一致,即算多条)。
📌 举例说明(简洁AOE网):
事件:A(源点)、B、C、D(汇点)
活动(边)及权值:
A→B : 2
A→C : 3
B→D : 4
C→D : 3
计算:
- ve[A]=0, ve[B]=2, ve[C]=3, ve[D]=max(2+4, 3+3)=max(6,6)=6 → 总工期=6
- 检查路径:
A→B→D:长度=2+4=6
A→C→D:长度=3+3=6
→ 两条路径长度均为6,且顶点序列不同(ABD vs ACD)⇒ 存在两条关键路径。
此时 dp[A]=1,
dp[B] += dp[A] =1(因 ve[A]+2ve[B]),
dp[C] += dp[A] =1(因 ve[A]+3ve[C]),
dp[D] += dp[B] + dp[C] =1+1=2 ⇒ dp[D]=2,确认多条关键路径。
进一步观察:B和C均满足 ve[x]==vl[x](可验证 vl[D]=6, vl[B]=6−4=2, vl[C]=6−3=3, vl[A]=min(2,3)=0),故A、B、C、D均为关键事件;但关键活动是 A→B、B→D、A→C、C→D 全部四条——说明整个网络呈“并行双路径”结构,无冗余边。

305

被折叠的 条评论
为什么被折叠?



