前置知识:拓扑排序
关键路径
A
O
E
AOE
AOE网:在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销(如完成活动所需的时间),称之为用边表示活动的网络,简称
A
O
E
AOE
AOE网。
A
O
E
AOE
AOE网和
A
O
V
AOV
AOV网都是有向无环图,不同之处在于它们的边和顶点所代表的含义是不同的,
A
O
E
AOE
AOE网中的边有权值,而
A
O
V
AOV
AOV网中的边无权值,仅表示顶点之间的前后关系。(E
是Edge
,V
是Vertex
)
A
O
E
AOE
AOE网具有以下两个性质:
- 只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始;
- 只有在进入某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发生。
源点&汇点:在
A
O
E
AOE
AOE网中仅有一个入度为
0
0
0的顶点,称为开始顶点(源点),它表示整个工程的开始;也仅有一个出度为
0
0
0的顶点,称为结束顶点(汇点),它表示整个工程的结束。
关键路径&关键活动:在
A
O
E
AOE
AOE网中,有些活动是可以并行进行的。从源点到汇点的有向路径可能有多条,并且这些路径的长度可能不同。完成不同路径上的活动所需的时间虽然不同,但是只有所有路径上的活动都已完成,整个工程才能算结束。因此,从源点到汇点的所有路径中,具有最大路径长度的路径称为关键路径,而把关键路径上的活动称为关键活动。
完成整个工程的最短时间就是关键路径的长度,即关键路径上各活动花费开销的总和。这是因为,关键活动影响了整个工程的时间,若关键活动不能按时完成,则整个工程的完成时间就会延长。因此,只要找到了关键活动,就找到了关键路径,也就可以得出整个工程的最短完成时间。
下面是几个寻找关键活动时要用的一些参量。
1.事件 v k v_k vk的最早发生时间 v e ( k ) v_e(k) ve(k)
它指的是从源点 v 1 v_1 v1到顶点 v k v_k vk的最长路径长度。事件 v k v_k vk的最早发生时间决定了所有从 v k v_k vk开始的活动能够开工的最早时间。可用下面的递推公式来计算:
- v e ( 源点 ) = 0 v_e(\text{源点})=0 ve(源点)=0
- v e ( k ) = M a x { v e ( j ) + W e i g h t ( v j , v k ) } v_e(k)=Max \{ v_e(j)+Weight(v_j,v_k) \} ve(k)=Max{ve(j)+Weight(vj,vk)}, v k v_k vk为 v j v_j vj的任意后继, W e i g h t ( v j , v k ) Weight(v_j,v_k) Weight(vj,vk)表示弧 ⟨ v j , v k ⟩ \left \langle v_j,v_k \right \rangle ⟨vj,vk⟩上的权值。
计算 v e ( ) v_e() ve()值时,可以在拓扑排序的基础上从前往后计算:
①初始时,令 v e [ 1 ⋯ n ] = 0 v_e[1 \cdots n]=0 ve[1⋯n]=0。
②输出一个入度为 0 0 0的顶点 v j v_j vj时,计算它所有直接后继顶点 v k v_k vk的最早发生时间,若 v e [ j ] + W e i g h t ( v j , v k ) > v e [ k ] v_e[j]+Weight(v_j,v_k)>v_e[k] ve[j]+Weight(vj,vk)>ve[k],则 v e [ k ] = v e [ j ] + W e i g h t ( v j , v k ) v_e[k]=v_e[j]+Weight(v_j,v_k) ve[k]=ve[j]+Weight(vj,vk)。以此类推,直至输出全部顶点。
2.事件 v k v_k vk的最迟发生时间 v l ( k ) v_l(k) vl(k)
它指的是在不推迟整个工程完成的前提下,即保证它的后继事件 v j v_j vj在其最迟发生时间 v l ( j ) v_l(j) vl(j)能够发生时,该事件最迟必须发生的时间。可用下面的递推公式来计算:
- v l ( 汇点 ) = v e ( 汇点 ) v_l( \text{汇点} )=v_e( \text{汇点} ) vl(汇点)=ve(汇点)
- v l ( k ) = M i n { v l ( j ) − W e i g h t ( v k , v j ) } v_l(k)=Min \{ v_l(j)-Weight(v_k,v_j) \} vl(k)=Min{vl(j)−Weight(vk,vj)}, v k v_k vk为 v j v_j vj的任意前驱
计算 v l ( k ) v_l(k) vl(k)值时,可以在逆拓扑排序的基础上从后往前计算:
①初始时,令 v l [ 1 ⋯ n ] = v e [ n ] v_l[1 \cdots n]=v_e[n] vl[1⋯n]=ve[n]。
②可设一个栈保存拓扑排序序列,自栈顶至栈底则为逆拓扑排序序列。计算时,栈顶顶点 v j v_j vj出栈,计算其所有直接前驱顶点 v k v_k vk的最迟发生时间,若 v l [ j ] − W e i g h t ( v k , v j ) < v l [ k ] v_l[j]-Weight(v_k,v_j)<v_l[k] vl[j]−Weight(vk,vj)<vl[k],则 v l [ k ] = v l [ j ] − W e i g h t ( v k , v j ) v_l[k]=v_l[j]-Weight(v_k,v_j) vl[k]=vl[j]−Weight(vk,vj)。以此类推,直至栈空。
3.活动 a i a_i ai的最早开始时间 e ( i ) e(i) e(i)
它指的是该活动弧的起点所表示的事件的最早发生时间。若边 ⟨ v k , v j ⟩ \left \langle v_k,v_j \right \rangle ⟨vk,vj⟩表示活动 a i a_i ai,则有 e ( i ) = v e ( k ) e(i)=v_e(k) e(i)=ve(k)。
4.活动 a i a_i ai的最迟开始时间 l ( i ) l(i) l(i)
它指的是该活动弧的终点所表示的事件的最迟发生时间与该活动所需时间之差。若边 ⟨ v k , v j ⟩ \left \langle v_k,v_j \right \rangle ⟨vk,vj⟩表示活动 a i a_i ai,则有 l ( i ) = v l ( j ) − W e i g h t ( v k , v j ) l(i)=v_l(j)-Weight(v_k,v_j) l(i)=vl(j)−Weight(vk,vj)。
5.一个活动 a i a_i ai的最迟开始时间 l ( i ) l(i) l(i)和其最早开始时间 e ( i ) e(i) e(i)的差额 d ( i ) = l ( i ) − e ( i ) d(i)=l(i)-e(i) d(i)=l(i)−e(i)
它是指该活动完成的时间余量,即在不增加完成整个工程所需总时间的情况下,活动
a
i
a_i
ai可以拖延的时间。若一个活动的时间余量为0
,则说明该活动必须要如期完成,否则就会拖延整个工程的进度,所以称
l
(
i
)
−
e
(
i
)
=
0
l(i)-e(i)=0
l(i)−e(i)=0即
l
(
i
)
=
e
(
i
)
l(i)=e(i)
l(i)=e(i)的活动
a
i
a_i
ai是关键活动。
求关键路径的实例
求关键路径的算法步骤如下:
- 从源点出发,令 v e ( 源点 ) = 0 v_e( \text{源点} )=0 ve(源点)=0,按拓扑有序求其余顶点的最早发生时间 v e ( ) v_e() ve()。
- 从汇点出发,令 v l ( 汇点 ) = v e ( 汇点 ) v_l( \text{汇点} )=v_e( \text{汇点} ) vl(汇点)=ve(汇点),按逆拓扑有序求其余顶点的最迟发生时间 v l ( ) v_l() vl()。
- 根据各顶点的 v e ( ) v_e() ve()值求所有弧的最早开始时间 e ( ) e() e()。
- 根据各顶点的 v l ( ) v_l() vl()值求所有弧的最早开始时间 l ( ) l() l()。
- 求 A O E AOE AOE网中所有活动的差额 d ( ) d() d(),找出所有 d ( ) = 0 d()=0 d()=0的活动构成关键路径。
下图是王道书上的一个实例。(图片来自王道考研408数据结构2025)
缩短工期
对于关键路径,需要注意以下几点:
1
)
1)\text{\ }
1) 关键路径上的所有活动都是关键活动,它是决定整个工程的关键因素,因此可以通过加快关键活动来缩短整个工程的工期。但是也不能任意缩短关键活动的所需时间,因为一旦缩短到一定程度,该关键活动可能就会变成非关键活动。
2
)
2)\text{\ }
2) 网中的关键路径可能并不唯一。对于有几条关键路径的网,只提高一条关键路径上的关键活动速度并不能缩短整个工程的工期,只有加快那些包括在所有关键路径上的关键活动,才能达到缩短工期的目的。
这一节全是八股文,应该只要会手推一个
A
O
E
AOE
AOE网的关键路径就行,结合课后练习加深理解即可。
以上。