分类: C/C++
1. 拓扑排序
1) 无环图:
一个无环的有向图称为无环图(Directed Acyclic Graph),简称DAG图。
所有的工程或者某种流程都可以分为若干个小的工程或者阶段,称这些小的工程或阶段为“活动”。
这些子程序之间存在一定的约束,其中某种子工程的开始必须在另一些子工程完成之后。因此DAG图表示一个工程,其中有向边表示约束关系。这种有向图必须是无环的。如果出现了环(有向环),那么向前递推,环路上的任一子工程开始的先决条件必然是自己,显然矛盾的。如果设计出这样的工程图,工程无法进行。拓扑排序就是测试一个工程能否顺利进行。
若以图中的顶点来表示活动,有向边表示活动之间的优先关系,则这样的有向图称为 AOV(Activity On Vertex network) 网。在 AOV 网中,若从顶点 v i 到顶点 v j 之间存在一条有向路径,称顶点 v i 是顶点 v j 的前趋,或者称顶点 v j 是顶点 v i 的后继。
2)对 AOV 网进行拓扑排序的方法和步骤如下:
(1)从 AOV 网中选择一个没有前趋的顶点(该顶点的入度为 0 )并且输出它;
(2)从网中删去该顶点,并且删去从该顶点发出的全部有向边;
(3)重复上述两步,直到剩余网中不再存在没有前趋的顶点为止。
3)操作的结果有两种:
一种是网中全部顶点都被输出,这说明网中不存在有向回路,拓扑排序成功;
另一种是网中顶点未被全部输出,剩余的顶点均有前趋顶点,这说明网中存在有向回路,不存在拓扑有序序列。
4)算法:
为了避免在每一步选入度为零的顶点时重复扫描表头数组,利用表头数组中入度为零的顶点域作为链栈域,存放下一个入度为零的顶点序号,零表示栈底,栈顶指针为 top ,寄生在表头数组的入度域中的入度为零的顶点:
拓朴排序算法梗概如下:
(1)扫描顶点表,将入度为零的顶点入栈;
(2)While ( 栈非空 )
{ 将栈顶点 v j 弹出并输出之;
在邻接链表中查 v j 的直接后继 v k ,把 v k 的入度减 1 ,若 v k 的入度为零则进栈;
}
5)算法的时间复杂度
对一个具有 n 个顶点, e 条边的网来说,初始建立入度为零的顶点栈,要检查所有顶点一次,执行时间为 O(n) ;排序中,若 AOV 网无回路,则每个顶点入、出栈各一次,每个表结点被检查一次,因而执行时间是 O(n+e) 。所以,整个算法的时间复杂度是 O(n+e) 。
2.关键路径
若在带权的有向图中,以顶点表示事件,以有向边表示活动,边上的权值表示活动的开销(如该活动持续时间),则此带权的有向图称为边表示活动的网 (Activity on Edge Network) ,简称 AOE 网。
1) AOV 网具有的性质
(1)只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始。
(2)只有在进入某一顶点的各有向边所代表的活动都已经结束,该顶点所代表的事件才能发生。
(3)表示实际工程计划的 AOE 网应该是无环的,并且存在唯一的入度过为 0 的开始顶点和唯一的出度为 0 的完成顶点。
2)关键活动:
由事件 v j 的最早发生时间和最晚发生时间的定义 , 可以采取如下步骤求得关键活动 :
(1)从开始顶点 v 1 出发 , 令 ve(1)=0, 按拓朴有序序列求其余各顶点的可能最早发生时间。
Ve(k)=max{ve(j)+dut()} 其中dut(表示顶点Vj到顶点Vk所持续的时间;
j ∈ T
其中 T 是以顶点 v k 为尾的所有弧的头顶点的集合 (2 ≤ k ≤ n) 。
如果得到的拓朴有序序列中顶点的个数小于网中顶点个数 n ,则说明网中有环,不能求出关键路径,算法结束。
(2)从完成顶点 v n 出发,令 vl(n)=ve(n) ,按逆拓朴有序求其余各顶点的允许的最晚发生时间 :
vl(j)=min{vl(k)-dut()}
k ∈ S
其中 S 是以顶点 v j 是头的所有弧的尾顶点集合 (1 ≤ j ≤ n-1) 。
(3)求每一项活动 a i (1 ≤ i ≤ m) 的最早开始时间 e(i)=ve(j) ;最晚开始时间
l(i)=vl(k)-dut()
若某条弧满足 e(i)=l(i) ,则它是关键活动。
求出 AOE 网中所有关键活动后,只要删去 AOE 网中所有的非关键活动,即可得到 AOE 网的关键路径。
这时从开始顶点到达完成顶点的所有路径都是关键路径。一个 AOE 网的关键路径可以不止一条。
3)注意:
并不是加快任何一个关键活动都可以缩短整个工程完成的时间,只有加快那些包括在所有的关键路径上的关键活动才能达到这个目的。只有在不改变 AOE 网的关键路径的前提下,加快包含在关键路径上的关键活动才可以缩短整个工程的完成时间。