一.AOE网:
1.概述:

注:Edge译为边。
以上述图片为例,
现在要做番茄炒蛋,假设已经有原材料,
首先需要花2分钟的时间"打鸡蛋",花1分钟的时间"洗番茄",洗番茄后还需要花3分钟的时间"切番茄","切番茄"、"打鸡蛋"之后还需要花2分钟的时间"炒菜",
"打鸡蛋"、"洗番茄"、"切番茄"、"炒菜"表示活动,是利用边来表示,并且用边上的权值来表示完成当前活动所需要的时间开销,可以理解为各个活动需要持续一段时间,
各个顶点表示事件,这些事件的发生就是一瞬间的事情,
AOE网性质举例:
-
性质1:只有"开始"事件发生之后,才能进行"打鸡蛋"、"洗番茄"这两个活动;只有"可以炒了"事件发生之后,才能进行"炒菜"活动
-
性质2:只有完成"打鸡蛋"、"切番茄"这两个活动才能进行"可以炒了"事件;如果番茄炒蛋有多个人同时完成,"打鸡蛋"和"洗番茄"这两个活动就可以同时进行,但是"洗番茄"和"切番茄"这两个活动不能同时进行,因为只有"洗番茄"结束后才能开始"切番茄"
2.概念:

以上述图片为例,
顶点V1就是开始顶点(源点),指整个工程从V1开始;
顶点V4就是结束顶点(汇点),指整个工程在V4结束。
二.关键路径:(注:顶点表示事件,有向边表示活动)
1.概念:

以上述图片为例,
开始顶点(源点)为V1,结束顶点(汇点)为V4,在AOE网中从V1到V4可以找到多条路径,
包括V1->V3->V4,该路径总长度为4;V1->V2->V3->V4,该路径总长度为6,
所有的这些从开始顶点(源点)V1到结束顶点(汇点)V4的路径中具有最大长度的路径就是关键路径,关键路径上的活动就是关键活动,因此路径V1->V2->V3->V4是关键路径,
完成整个工程的最短时间就是关键路径的长度,
上述图片的例子中关键路径V1->V2->V3->V4的总长度为6,意味着做完"番茄炒蛋"最少需要6分钟的时间("打鸡蛋"和"洗番茄"、"切番茄"可以同时进行,意味着做"洗番茄"、"切番茄"的同时可以"打鸡蛋",时间也就不用叠加),
对于关键路径上的活动即关键活动,之所以叫关键活动,是因为如果这几个活动不能按时完成,那么整个工程的完成时间就会延长,比如"炒菜"活动没有按照2分钟按时完成,而是花了3分钟,那么完成V1->V2->V3->V4这个工程就需要1+3+3=7分钟,比正常多了1分钟。
所以在一个复杂的工程中,每一个活动之间可能存在前后的依赖关系,在这种复杂的工程中找到关键路径、关键活动是很有现实意义的,因为找到关键活动意味着能够知道影响整个工程进度的最重要的是哪些活动,那么在做这些关键活动时就需要争分夺秒。
2.实例:

如上图,
假设现在非常的饿,到了一家饭店,
首先问"最快多久可以开始做饭",老板说"现在,马上!",也就是说"开始"这个事件可以在0时刻就发生,
接下来又问"最快多久可以开始切番茄",这时就需要从0时刻开始算起,需要"洗番茄"后才可以开始"切番茄",所以1分钟后就可以开始"切番茄",
接下来问"最快多久可以开炒","切番茄"需要3分钟的时间,"切番茄"之前又需要"洗番茄","洗番茄"需要1分钟的时间,所以准备好番茄总共需要4分钟的时间,但"开炒"之前还需要准备鸡蛋,"打鸡蛋"从0时刻就可以开始,"打鸡蛋"需要2分钟的时间,所以到第4分钟的时候鸡蛋也准备好了(注:准备番茄的同时可以准备鸡蛋,同时准备是最快的,如果鸡蛋、番茄分开准备就会多花时间),因此最快4分钟就可以"开炒",
最后问"最快多久可以吃",也就是什么时候发生事件"结束",显然到达事件V3最快需要4分钟,接下来还需要2分钟的时间"炒菜",所以最快6分钟就可以"吃",
事件vk的最早发生时间ve(k)->决定了所有从vk开始的活动能够开工的最早时间。刚才从开始顶点(源点)V1推出各个事件发生的最短时间,每一个事件发生的最短时间决定了从这个事件开始的那些活动能够开工的最早时间,
活动ai的最早开始时间e(i)->其实每个活动最早的开始时间就是它的弧尾连接的事件的最早发生时间,比如"洗番茄"活动最早可以从0时刻开始,"切番茄"最早可以从第1分钟开始,"炒菜"最早可以从第4分钟开始,
所以只要确定了各个事件的最早发生时间,那么就可以根据这个信息来确定每一个活动的最早开始时间,
如下图:

如上图,
假设此时饥饿值达到最大,如果在预期的最快完成时间6分钟内无法"结束",那么就会饿死,
6分钟之后必须进行事件"结束","结束"之前的活动"炒菜"总共需要花费2分钟的时间
->通过逆推可知事件"可以炒了"必须要在4分钟之后发生,如果4分钟之后事件"可以炒了"没有发生,那么到第6分钟的时候就无法"结束","可以炒了"之前的一个活动"切番茄"总共需要花费3分钟的时间
->通过逆推可知事件"可以切了"必须要在1分钟之后发生,"可以切了"之前的一个活动"洗番茄"总共需要花费1分钟的时间
->通过逆推可知事件"开始"必须要从0时刻开始即立马开始,
刚才从后依次往前推,推出了每一个事件允许发生的最迟的时间,这些事件只有在给出的时间点内发生,才能保证最后工程是按期结束的,根据事件vk的最迟发生时间vl(k)可以得到活动ai的最迟开始时间l(i),
比如活动"打鸡蛋",它后面的事件"可以炒了"必须要在4分钟之后发生,而"打鸡蛋"总共需要花费2分钟的时间,所以最晚可以在第2分钟之后开始"打鸡蛋",到第4分钟刚好不拖累事件"可以炒了"发生,
也就是说虽然从0时刻就开始做菜,但是其实没有必要一开始就赶着"打鸡蛋","打鸡蛋"可以在第3、4分钟进行,但"切番茄"总共需要3分钟,而他之后的事件"可以炒了"必须在第4分钟就发生,因此"切番茄"这个活动必须在第4-3=1分钟就开始进行,不能比这个更晚,
所以结合各个事件所允许的最迟发生时间,可以推出每一个活动的最迟开始时间。
现在把活动ai的最早开始时间e(i)和活动ai的最迟开始时间l(i)放在一起,
如下图:

如上图,
会发现只有"打鸡蛋"这个活动可以在第1、2分钟进行(0时刻就开始),也可以在第3、4分钟进行(第2时刻开始),
然而对于其余的活动所允许的最早开始时间e(i)和最迟开始时间l(i)都是一样的,也就是说这几个活动是不能拖延的,一旦拖延,整个工程的完成时间就会延后,
把活动ai的最迟开始时间l(i)和最早开始时间e(i)进行相减,结果记为d(i),称为时间余量,也就是在整个工程中时间不延后的情况下,活动ai可以拖延的时间,
对于时间余量d(i)为0的活动,其实就是关键活动,必须按期完成,不能拖延,
只要找到了关键活动,最终就可以确定AOE网中的关键路径。
3.求关键路径的步骤:

(e即early,l即late)
如上图,
步骤一:从开始顶点(源点)依次往后推算出所有事件的最早发生时间ve,比如时间V5所代表的事件最早的发生时间用ve(5)记录->有了事件的最早发生时间ve,就可以推出对应活动的最早发生时间e->ve=e;
步骤二:从结束顶点(汇点)逆推出所有事件的最迟发生时间vl->有了事件的最迟发生时间vl,就可以推出对应活动的最迟发生时间l;
步骤三:把活动对应的最早发生时间e和活动对应的最迟发生时间l相减可以得出活动对应的时间余量d->时间余量d为0的活动就是关键活动,找到了关键活动也就是找到了各个有向边就可以确定关键路径;
4.求关键路径的详解:

以上述图片为例,
步骤一:求所有事件的最早发生时间ve->

如上图,
首先需要对AOE网进行拓扑排序(详情见"6.13.拓扑排序"),使用拓扑排序序列是为了让计算过程有序进行,拓扑排序得到的序列不唯一,取其中一个即可,本次取V1、V3、V2、V5、V4、V6,
再根据拓扑排序的序列来依次计算各个顶点所代表的事件的最早发生时间ve:
Ⅰ.首先求开始顶点(源点)V1,它的最早发生时间就是0即ve(1)=0,因为是开始顶点(源点)->所以V1的最早发生时间是0分钟之后;
Ⅱ.接下来求V3,除了开始顶点(源点)之外其他的所有顶点都至少有一个直接前驱,V3的最早发生时间就是它的前驱顶点V1的最早发生时间加上V1到达V3的活动所需要的时间即ve(3)=ve(1)+a₂=0+2=2->所以V3的最早发生时间是2分钟之后;
Ⅲ.接下来求V2,V2的最早发生时间就是它的前驱顶点V1的最早发生时间加上V1到达V2的活动所需要的时间即ve(2)=ve(1)+a₁=0+3=3->所以V2的最早发生时间是3分钟之后;
Ⅳ.接下来求V5,V5的最早发生时间就是它的前驱顶点V2的最早发生时间加上V2到达V5的活动所需要的时间即ve(5)=ve(2)+a₄=3+3=6->所以V5的最早发生时间是6分钟之后;
Ⅴ.接下来求V4,V4有两个直接前驱V2、V3,那么对于V4的最早发生时间需要分开考虑->
-
对于V4的第一个直接前驱V2,V2最早发生时间是在3分钟之后,V2结束后还需要经过2分钟的活动才能开始V4,因此从V1->V2->V4来看最早在5分钟之后就可以发生V4
-
对于V4的第二个直接前驱V3,V3最早发生时间是在2分钟之后,V3结束后还需要经过4分钟的活动才能开始V4,因此从V1->V3->V4来看最早在6分钟之后才可以发生V4
如果要开始V4,必须指向V4的所有活动和事件都结束才可以,又因为V1->V2->V4和V1->V3->V4可以同时进行,因此为了保证每一步都完成且是最早发生时间,显然要取最早发生时间更大的,所以V4的最早发生时间是6分钟之后(注:取5的话V1->V3->V4就无法完成,不符合题意)即ve(4)=max{ve(2)+2,ve(3)+4}=6;
Ⅵ.接下来求V6,V6有三个直接前驱V5、V4、V3,那么对于V6的最早发生时间需要分开考虑->
-
对于V6的第一个直接前驱V5,V5最早发生时间是在6分钟之后,V5结束后还需要经过1分钟的活动才能开始V6,因此从V1->V2->V5->V6来看最早在7分钟之后就可以发生V6
-
对于V6的第二个直接前驱V4,V4最早发生时间是在6分钟之后,V4结束后还需要经过2分钟的活动才能开始V6,因此从V1->V3->V4->V6来看最早在8分钟之后才可以发生V6
-
对于V6的第三个直接前驱V3,V3最早发生时间是在2分钟之后,V3结束后还需要经过3分钟的活动才能开始V6,因此从V1->V3->V6来看最早在5分钟之后就可以发生V6
如果要开始V6,必须指向V6的所有活动和事件都结束才可以,又因为V1->V2->V5->V6、V1->V3->V4->V6和V1->V3->V6可以同时进行,因此为了保证每一步都完成且是最早发生时间,显然要取最早发生时间更大的,所以V6的最早发生时间是8分钟之后即ve(6)=max{ve(5)+1,ve(4)+2,ve(3)+3}=8,
至此,就得到了所有事件有可能发生的最早时间。
步骤二:求所有事件的最迟发生时间vl->

如上图,
首先需要对AOE网进行逆拓扑排序(详情见"6.13.拓扑排序"),使用逆拓扑排序序列是为了让计算过程有序进行,逆拓扑排序得到的序列不唯一,取其中一个即可,本次取V6、V5、V4、V2、V3、V1,
再根据逆拓扑排序的序列来依次计算各个顶点所代表的事件的最迟发生时间vl:
Ⅰ.首先求结束顶点(汇点)V6,汇点所允许的最迟发生时间其实和它的最早发生时间是相等的,即ve(6)=vl(6)=8->所以事件V6的最迟发生时间是8分钟之后;
汇点所允许的最迟发生时间等于它的最早发生时间,证明如下:
首先要明确两个概念->已经进行完的事件不会再次进行;如果某个事件的出度大于1,那么该事件完成后会同时进行后面的几个事件;如果一个顶点直接指向另一个顶点,那么只会有一条路径,不会有多条,现实也是这样的,比如上图中V2指向V5和V4,因此进行完V2后,会同时执行V4、V5,而且也不会执行完V5后再执行一遍V2以执行V4,
V6是汇点即最后一个发生的顶点,意味着执行到V6时其他的所有顶点全部执行完毕,要使得其他的顶点全部执行完毕,就要保证所需时间最大的那一条路径执行完毕,因此汇点所允许的最迟发生时间等于它的最早发生时间。
Ⅱ.接下来求V5,V5的后继是V6,V6最迟在8分钟之后发生,V5到V6中间的活动a₈需要消耗1分钟的时间,所以事件V5最迟需要在7分钟之后发生,也就是用V6的最迟发生时间vl(6)减去a₈即vl(5)=vl(6)-a₈=8-1=7->所以事件V5的最迟发生时间是7分钟之后;
Ⅲ.接下来求V4,V4的后继是V6,V6最迟在8分钟之后发生,V4到V6中间的活动a₇需要消耗2分钟的时间,所以事件V4最迟需要在6分钟之后发生,也就是用V6的最迟发生时间vl(6)减去a₇即vl(4)=vl(6)-a₇=8-2=6->所以事件V4的最迟发生时间是6分钟之后;
Ⅳ.接下来求V2,V2有两个后继即V5、V4,首先看V5,事件V5的最迟发生时间是7分钟之后,V2到V5中间的活动a₄需要消耗3分钟的时间,所以事件V2最迟需要在4分钟之后发生;再看V4,事件V4的最迟发生时间是6分钟之后,V2到V4中间的活动a₃需要消耗2分钟的时间,所以事件V2最迟需要在4分钟之后发生,总之,V2的最迟发生时间vl(2)为vl(2)=min{ vl(5)-a₄,vl(4)-a₃ }=min{4,4}=4->所以事件V2的最迟发生时间是4分钟之后;(注:这里之所以取min,是因为在逆推,逆的时候越小,正的时候越大即越迟)
Ⅴ.接下来求V3,V3有两个后继即V4、V6,首先看V4,事件V4的最迟发生时间是6分钟之后,V3到V4中间的活动a₅需要消耗4分钟的时间,所以事件V3最迟需要在2分钟之后发生;再看V6,事件V6的最迟发生时间是8分钟之后,V3到V6中间的活动a₆需要消耗3分钟的时间,所以事件V3最迟需要在5分钟之后发生,总之,V3的最迟发生时间vl(3)为vl(3)=min{ vl(4)-a₅,vl(6)-a₆ }=min{2,5}=2->所以事件V3的最迟发生时间是2分钟之后;(注:这里之所以取min,是因为在逆推,逆的时候越小,正的时候越大即越迟)
Ⅵ.接下来求V1,V1有两个后继即V2、V3,首先看V2,事件V2的最迟发生时间是4分钟之后,V1到V2中间的活动a₁需要消耗3分钟的时间,所以事件V1最迟需要在1分钟之后发生;再看V3,事件V3的最迟发生时间是2分钟之后,V1到V3中间的活动a₂需要消耗2分钟的时间,所以事件V1最迟需要在0分钟之后发生,总之,V1的最迟发生时间vl(1)为vl(1)=min{ vl(2)-a₁,vl(3)-a₂ }=min{1,0}=0->所以事件V1的最迟发生时间是0分钟之后;(注:这里之所以取min,是因为在逆推,逆的时候越小,正的时候越大即越迟)
步骤三:求所有活动的最早发生时间e->
之前已经提及到每一个活动的最早发生时间e等于这个活动的弧尾连接的事件的最早发生时间ve,
由于之前已经求出所有事件的最早发生时间ve,所以只需要根据e=ve即可求出各个活动的最早发生时间e,
如下图:

如上图,
比如活动a₄,最早在3分钟的时候进行,
如下图:

步骤四:求所有活动的最迟发生时间l->

如上图,
求所有活动的最迟发生时间l需要基于之前求得的所有事件的最迟发生时间vl,
比如事件V6的最迟发生时间是8分钟之后,活动a₈需要消耗1分钟的时间,那么活动a₈最迟需要在7分钟之后发生,也就是用V6的最迟发生时间vl(6)减去a₈的权值即l(8)=vl(6)-a₈=8-1=7->所以活动a₈的最迟发生时间是7分钟这一刻,以此类推
->对于所有的活动,它的最迟发生时间l其实就是对应活动所在弧指向的顶点的最迟发生时间减去这条弧的权值。
步骤五:求所有活动的时间余量d->
只需要根据公式d(i)=l(i)-e(i),如下图:

如上图,
会发现活动a₂、a₅、a₇的时间余量d为0,也就是说活动a₂、a₅、a₇绝对不能拖延,只要活动a₂、a₅、a₇有一个拖延,那整个工程的工期一定要比预期的完成工期长,
因此,到这一步,就找到了所有的关键活动即a₂、a₅、a₇,
每一个活动对应一条弧,由活动a₂、a₅、a₇所对应的弧就找到了一条完整的关键路径即V1->V3->V4->V6,
如下图:

三.关键活动、关键路径的特性:

特性1:若关键活动耗时增加,则整个工程的工期将增长;
特性2:若缩短关键活动的时间,那么可以缩短整个工程的工期,以上述图片的AOE网为例,"炒菜"属于关键活动,需要消耗2分钟的时间,如果能把"炒菜"的时间缩短,那么就可以提前结束工程;
特性3:当某个关键活动耗时缩短到一定程度时,该关键活动可能会变成非关键活动,相应的关键路径也发生了改变,以上述图片的AOE网为例,"切番茄"属于关键活动,如果用1分钟的时间完成"切番茄",那完成番茄炒蛋只需要4分钟的时间,如果进一步压缩"切番茄"的时间,比如只需要消耗0.5分钟的时间,此时就无法使得整个工程更提前的结束了,因为此时以前这条关键路径V1->V2->V3->V4不再是关键路径,关键路径变为V1->V3->V4,V1->V3->V4总共需要消耗4分钟的时间,V1->V2->V3->V4总共需要消耗3.5分钟的时间,此时要想加快番茄炒蛋的速度的话,就需要压缩"打鸡蛋"或者"炒菜"的时间,如下图:->因此,并非关键活动的时间越压缩,整个工程的工期越提前


特性4:在某些AOE网中,可能有多条关键路径,以上述图片的AOE网为例,假设活动"打鸡蛋"需要消耗4分钟的时间,活动"洗番茄"和"切番茄"总共需要消耗4分钟的时间,所以V1->V3->V4和V1->V2->V3->V4这两条路径都需要消耗6分钟的时间,因此V1->V3->V4和V1->V2->V3->V4这两条路径都是关键路径,所以这种情况下只缩短一条关键路径上的关键活动的速度可能并不能缩短整个工程的工期,比如把"切番茄"缩短为1分钟,但是由于"打鸡蛋"和"炒菜"总共还是需要6分钟的时间,此时整个工程仍需要6分钟的时间才能完成,工期并没有缩短,为了缩短工期该怎么办呢?除非把多条关键路径上的这些活动的时间都压缩,这种方法可以加快整个工程的进度,还可以加快那些包含在所有关键路径上的关键活动,比如上述AOE网里的"炒菜","炒菜"被包含在所有的关键路径中,所以只压缩"炒菜"的时间,整个工程的工期可以得到缩短。
四.总结:



364

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



