AOE网和关键路径

AOE网

抽象地看,AOE网是一种无环的带权有向图,其中:

  • 顶点表示事件,有向边表示活动,边上的权值通常表示活动的持续时间。
  • 图中一个顶点表示的事件,也就是它的人边所表示的活动都已完成,它的出边所表示的活动可以开始的那个状态,把这一情况看作事件。

实际工程或复杂事务里的一批相关活动(工作项目、任务等),可以用一个AOE网描述(抽象),然后就可以基于这个网考虑活动的安排了。

 下图给出的AOE网中包括15项活动、9个事件。图中标的:ai:n表示该边代表的活动名ai为,权值为n。图中事件v0表示整个工程可以开始的状态;事件v4表示活动a5、a8已经完成,活动a10、a11可以开始的状态,事件v8表示整个工程结束。

图中显示,活动a0需要7个单位时间完成,活动需要a13个单位时间完成,等等。整个工程开始,活动a0、a1、a2就可以同时开始了,而活动a3、 a4需要等到事件v1发生后才能开始,a5、a6、a7要等到事件v2发生之后才能进行,如此等等。
当活动a12、a13、a14完成时,整个工程就完成了。

AOE网中描述的活动可以并行地进行,只要一项活动(一条边)的前提事件均已发生(也就是说,以该边的始点为终点的所有活动都已经完成),这项活动就可以开始。所以,完成整个工程的最短时间,就是从开始顶点到完成顶点的最长路径的长度(即,路径上各条边的权值之和)。这种最长路径称为AOE网的关键路径,AOE网上最重要的一项计算工作是找出其中的关键路径。

关键路径算法

现在考虑如何开发出一种方法,能确定AOE网G=(V,E)里的关键路径。下面假定顶点v0是G中的开始事件,vn-1是结束事件,w(<vi,vj>)为边<vi,vj>的权。
首先定义几组变量,用它们记录关键路径计算中确定的信息:

1)事件的最早可能发生时间ee[j]显然,这一时间要根据在它之前的事件(顶点)和相关活动(边及其权值)确定,不可能更早发生。ee[j]可以递推计算:
       ee[0]=0(初始事件总在时刻0发生)
       ee[j]=max{ee[i]+w(<vi,vj>)|<vi,vj>\inE},0\leqj\leqn-1

对每个j,只需要考虑以为vj终点的入边集。
2)事件vi的最迟允许发生时间le[i]。事件的发生有可能推迟更晚,但有些事件过迟发生就会延误整个工程的进度。可以根据已知的值反向地递推计算:
        le[n—l]=ee[n—1](最后一个事件绝不能再延迟)
        le[i]=min{le[j]+w(<vi,vj>)|<vi,vj>\inE},0\leqi\leqn-2

与上面类似,对每个i,只需要考虑以为始点的出边集。
3)在这个网络中活动ak=<vi,vj>的最早可能开始时间e[k]=ee[i],以及它的最迟允许开始时间l[k]=le[j]-w(<vi,vj>)(只要该活动的实际开始不晚于这个时间,就不会拖延整个工程的工期)。

活动集合,A={ak|e[k]=l[k]}中的所有活动称为这个AOE网里的关键活动,因为它们中的任何一个推迟开始,都会延误整个工程的工期。E-A中的活动为非关键活动。对于非关键活动,l[k]-e[k]不等于0,这个差表示开始活动的时间余量,这是在不延误整体工期的前提下,活动可以推迟开始的时限。所有完全由关键活动构成的从初始点到终点的路径就是图G中的关键路径。关键路径可能不止一条,可以同时得到。

关键路径算法的python实现

前面讨论中提出的关键路径算法,可以直截了当地翻译为一个Python实现,其中一步步计算出有关信息。在下面的实现中用两个list表示ee和le,它们都以AOE网中的顶点为下标,其中每项记录对应于一个事件的时间。

应该注意,为正确生成ee和le的数据,计算需要按一定的顺序进行。对于ee,只有算出了前面制约事件的ee值之后,才能进一步计算被制约事件的ee值。对le的计算顺序正好相反。不难看到,对ee的可行计算顺序就是AOE网上的拓扑顺序,可以按顶点的任何拓扑序列计算,而对le的正确计算顺序就是逆拓扑顺序,可以按拓扑序列反向计算。因此,在正式开始计算之前,需要先得到该AOE网的一个拓扑序列。
算法实现分为下面几步:
1)生成AOE网的一个拓扑序列。
2)生成ee表的值,应该按拓扑序列的顺序计算。
3)生成le数组的值,应该按拓扑序列的逆序计算。
4)最后,数据组e和1可以一起计算(很简单)。由于只希望得到关键路径,下面并不显式表示这两组数据,而是直接求出关键活动。
在下面算法里,步骤1直接调用前面的拓扑排序过程,步骤2和3定义为独立的内部过程,最后一步直接计算并收集确定的关键活动,函数返回得到的所有关键活动可能表示多条关键路径:

def critical_paths(graph):
    def event_earliest_time(vnum,graph,toposeq):
        ee=[0]*vnum
        for i in toposeq:
            for j,w in graph.out_edges(i):
                if ee[i]+w>ee[j]:           #时间j更晚结束
                    ee[j]=ee[i]+w
        return ee

    def event_latest_time(vnum,graph,toposeq,eelast):
        le=[eelast]*vnum
        for k in range(vnum-2,-1,-1):       #逆拓扑序列
            i=toposeq[k]
            for j,w in graph.out_edges(i):
                if le[j]-w<le[i]:           #事件i应更早开始
                    le[i]=le[j]-w
        return le

    def crt_paths(vnum,graph,ee,le):
        crt_actions=[]
        for i in range(vnum):
            for j,w in graph.out_edges(i):
                if ee[i]==le[j]-w:
                    crt_actions.append((i,j,ee[i]))
        return crt_actions

    toposeq=toposort(graph)
    if not toposeq:             #不存在拓扑序列,失败结束
        return False
    vnum=graph.vertex_num()
    ee=event_earliest_time(vnum,graph,toposeq)
    le=event_latest_time(vnum,graph,toposeq,ee[vnum-1])
    return crt_paths(vnum,graph,ee,le)

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值