数据结构复习笔记 关键路径+Critical+paths1. 关键路径 Critical Paths
刚对付了难缠的 AOV-网,又要来和它的破哥们儿 AOE-网斗志斗勇了。通缉它!
AOE 网—Activity On Edge
顶点----事件
边------活动
权------活动持续的时间
事件 i 发生后, 其后继活动 a(i,*)都可以开始;只有所有先导活动 a(*,j)
都结束后,事件 j 才发生。
教材 P183 对 AOE-网的解释很清晰。
1
2. 问题:a) 整个工程完工需要多长时间? b) 哪些活动影响工程的进度?或求关键路径。
请注意看一下上面的那些相关定义和名词解释,一定要看懂弄明白。
关键路径就是路径长度最长的路径。 你可能听过短板效应, 这里其实也是这种效应的变形吧,
只不过取决于最长的那些事情。 总有一些东西是关键。 下面的表示可能和教材稍微有一点差
别。不过,应该更容易理解。
事件(顶点) i: 最早发生时间 ve(i),最晚发生时间 vl(i);
活动(边) a(i,j):最早开始时间 e(i,j),最晚开始时间 l(i,j)。
于是,整个工程完工的时间就是终点的最早发生时间;关键路径就是路径长度最长的路径。
弄明白下面的几个关系:
1、关键活动就是 e(i)=l(i)的活动。
2、活动的最早发生时间 e(i,j)与事件的最早发生时间
ve(i)有关,且 e(i, j ) = ve(i), 。想也能想明白,事件最早什
么时候开始当然取决于事件最早什么时候开始了,不然它
自己开始个头头啊。
3、活动 a(i,j)的最晚开始时间 l(i,j)取决于 a(i,j)所连接的前后两个活动中的后一个活
动的最晚开始时间,以及这个活动能够持续的时间,即 l (i, j ) = vl ( j ) − a(i, j ) 。就是后面的课代
表一拖再拖最迟能够在周四收作业, 你写数据结构作业还有有两天, 当然你最晚要在周二开
始写啦,当然如果不写那就是另外的事情了。
上面的只是它们的关系,如何求才 ve(i)和 vl(i)才是最重要的东东。
算法:
1、求关键路径的第一步是计算出 AOE-网的拓扑有序序列,逆拓扑有序自然也就出来了。没
有了拓扑序列的技术支持,有可能做对,但是很悬。为了那将要来之不易的分数,好好的把
拓扑排序序列列出来吧。
2、从源点 ve(0)=0 开始按照拓扑有序求其余各个顶点的最早发生时间 ve(i)。
计算 ve(j):
⎧ve (1) = 0, ,其中*为任意前驱事件;
⎨
⎩ve ( j ) = max{ve (*) + a (*, j)}
即求顶点 j(上图中后一个顶点) 的 ve(j),就是将所有指向这个顶点的边中,从起点计算
权值之和,ve(j)去其中最大的。
重复一下,从源点开始直至汇点,依次按照拓扑有序计算。
3、从汇点 vn 出发,令这个顶点的最早开始时间 ve(n-1)和最晚开始时间 vl(n-1)相同(本
来就一样的) 。然后按照逆拓扑有序进行往前推导。
计算 vl(i):
⎧vl (n ) = ve (n ), 其中*为任意后继事件;
⎨
⎩vl (i ) = min{vl (*) − a (i ,*)}
求顶点 i 的 vl(i)就是将所有从这个顶点出发边中,用紧跟的顶点的最晚开始时间减去
权值,选择最小的即可。因为是按照逆拓扑有序进行,因此后面的顶点的最晚时间是已
经被算出的。
2
3. 4、根据各个顶点的 ve 和 vl 值,求出每条弧的最早开始时间和最晚开始时间,若某条
弧满足两个相等,就是关键活动。最终的关键活动可能有多条路线。
计算 e(i,j)和 l(i,j):
e (i , j ) = ve (i ), ,工程总用时 ve(n),关键活动是 e(i,j)=l(i,j)的活动 a(i,j)。
l (i , j ) = vl ( j ) − a (i , j )
说明:
10. 若只求工程的总用时只要进行步骤(a)-(b)即可求得。
20. 如何理解计算 ve(j)和 vl(i)的公式:
事件 j 在所有前驱活动都完成后发生,所以其最早 a(*,j) j i a(i,*)
发生时间 ve(j) = max{ve(*)+a(*,j)},即取决于最慢的
前驱活动。另一方面,事件 i 发生后所有后继活动都可以开始了,所以其最晚发生时间
vl(i) = min{vl(*)-a(i,*)},即不耽误最慢的后继活动。
例:某工程的 AOE 网如下,求 1) 整个工程完工需要多长时间,2) 关键路径。说明:图中
的虚线仅表示事件的先后关系,不代表具体活动。
1 5
2 5 7 2
6 1 3
4 9
1 3 8 4
5 4
1
4 6
分析:按照拓扑有序排列顶点,然后“从前往后”计算事件的最早发生时间得到总时间, 再
“从后往前” 计算事件的最晚发生时间,最后计算活动的最早和最晚开始时间得到关键活动
和关键路径。
表 7.2 关键路径
事件 最早发生时间 ve 最晚发生时间 vl 活动 最早开始时间 最晚开始时间
e l
v1 0 0 a(1,2) 0 0
v2 6 6 a(1,3) 0 2
v3 4 6 a(1,4) 0 1
v4 5 6 a(2,5) 6 6
v5 7 7 a(3,5) 4 6
v6 7 7 a(4,6) 5 6
v7 12 13 a(5,6) 7 7
v8 11 11 a(5,7) 7 8
v9 15 15 a(5,8) 7 8
a(6,8) 7 7
a(7,9) 12 13
a(8,9) 11 11
所以,1) 工程完工需要时间 15,2) 关键路径是 1�2�5�6�8�9。
同样,教材 P186 的例子也非常好,习题集 7.10 可以认真做一下,题目出的比较好。
从应试的角度看,求关键路径重要的是能够正确的画出上面的表格。但是算法可以更好
3
4. 的理解里面的细节。
Status TopologicalOrder(ALGraph G, Stack &T)
{FindInDegree(G, indegree); //对各顶点求入度 indegree
InitStack(S); //建零入度顶点栈 S
将入度为 0 的顶点入 S 栈;
InitStack(T); count = 0;
ve[0..G.vexnum - 1] = 0; // 初始化
While (! StackEmpty(S))
{ Pop(S, j); Push(T,j); ++count; //j 号顶点入 T 栈并计数
for(p=G.vertices[j].firstarc;p;p=p->nextarc)
{k = p->adjvex; // 对 j 号顶点的每个邻接点的入度减 1
if(--indegree[k]==0)Push(S, k); //若入度减为 0,则入栈
if(ve[j]+*(p->info)>ve[k])ve[k]=ve[j]+*(p->info);
}// *(p->info)= dut(<j,k>)
}// while
if(count<G.vexnum) return ERROR; //该有向网有回路
else return OK;
}// TopologicalOrder
Status CriticalPath(ALGraph G)
{ //G 为有向网,输出 G 的各项关键活动
if(!TopologicalOrder(G,T)) return ERROR;
vl[0..G.vexnum-1]=ve[0..G.vexnum-1];
//初始化顶点事件的最迟发生时间
while (! StackEmpty(T)) //按拓扑逆序求各顶点的 v1 值
for(Pop(T,j),p=G.vertices[j].firstarc; p; p=p->nextarc)
{k=p->adjvex; dut = * (p->info); // dut<j,k>
if(vl[k]-dut<v1[j]) vl[j] = vl[k]-dut;
}// for
for(j=0;j<G.vexnum; ++j) // 求 ee,e1 和关键活动
for(p=G.vertices[j].firstarc; p; p = p->nextarc)
{ k = p->adjvex; dut = * (p->info) ;
ee=ve[j]; el=vl[k]-dut; tag=(ee==e1)? '*' : '' ;
printf ( j,k, dut, ee, el, tag); // 输出关键活动
}
}// CriticalPath
4