Alex_McAvoy的博客

I'm not there,I'm not die.

AOV网、拓扑排序以及关键路径

【AOV网】

日常生活中,一项大的工程可以看作是由若干个子工程组成的集合,这些子工程之间必定存在一定的先后顺序,即某些子工程必须在其他的一些子工程完成后才能开始。

我们用有向图来表现子工程之间的先后关系,子工程之间的先后关系为有向边,这种有向图称为“顶点活动网络”,即:AOV网。

一个AOV网必定是一个有向无环图,即不带有回路。


【基本概念】

  1. 活动:子工程组成的集合,每个子工程即为一个活动。
  2. 前驱活动:有向边起点的活动称为终点的前驱活动(只有当一个活动的前驱全部都完成后,这个活动才能进行)。
  3. 后继活动:有向边终点的活动称为起点的后继活动。
  4. 拓扑排序:将AOV网中所有活动排成一个序列,使得每个活动的前驱活动都排在该活动的前面。
  5. 拓扑序列:经过拓扑排序后得到的活动序列(一个AOV网的拓扑序列不是唯一的)。

【拓扑排序思想】

  1. 选择一个入度为0的顶点并输出。
  2. 从AOV网中删除此顶点及以此顶点为起点的所有关联边。
  3. 重复上述两步,直到不存在入度为0的顶点为止。
  4. 若输出的顶点数小于AOV网中的顶点数,则说明AOV网中回路,不是一个标准的AOV网。

【拓扑排序实现】

struct node   
{  
    int adjvex;  
    node* next;  
}adj[N];  
void topsort(node adj[],int n)  
{  
    int count=0;  
    while(mystack.size()!=0)//栈非空
    {  
        
        v=mystack.top();
        cout<<v<<' ';//输出栈顶顶点v
        mystack.pop();//栈顶顶点出栈
        count++;//计数器+1
        
        for(int p=adj[v].next;p!=NULL;p=p->next)//枚举当前点的后继结点k
        {  
            int k=p->adjvex;  
            indegree[k]--;//k的入度减1
            if(indegree[k]==0)//入度为0,入栈
                mystack.push(k);  
        }  
    }  
    if(count<n)//如果输出顶点数小于AOV网的顶点数,说明有回路
        cout<<"有回路"<<endl;  
}

【算法分析】

以下图为例

开始时,只有A 入度为0,A入栈。

栈:A

栈顶元素A出栈,输出A,A的后继节点B、C入度减1(相当于删除A的所有关联边)。

栈:空

拓扑序列:A

B、C入度都为0,依次将B、C入栈

栈:BC(入栈顺序不唯一)

拓扑序列:A

栈顶元素C出栈,输出C,C的后继结点D入度减1(相当于删除C的所有关联边)。

栈:B

拓扑序列:AC

栈顶元素B出栈,输出B,B的后继结点D入度减1(相当于删除B的所有关联边),此时D的入度为0,入栈。

栈:D

拓扑序列:ACB

栈顶元素D出栈,输出D。栈空,排序结束。

栈:空

拓扑序列:ACBD(不唯一)

【关键路径】

源点

    整个工程的开始,只有出边没有入边,通常选取第一个活动(活动1)作为源点。

汇点

    整个工程的结束,只有入边没有出边,通常选取最后一个活动(活动n)作为汇点。

事件的最早发生时间与活动最早开始时间

    如图,事件Vj必须在它的所有入边活动Eik(i<=k<=n)都完成后才能发生,活动Eik(1<=k<=n)的最早开始时间是与它对应的起点事件Vik的最早发生时间。所有以事件Vj为起点活动的出边活动Ejk (1<=k<=n)的最早开始时间都等于事件Vj的最早发生时间。


所以,我们可以从源点出发按照上述方法,求出所有事件的最早发生时间。

设数组earliest[1...n]表示所有事件的最早发生时间,w[j][k]表示边<j,k>上的权值,且事件j是事件k的直接前驱事件,则我们可按照拓扑顺序依次计算出earliest[k]:

    earliest[1]=0,earliest[k]=max{earliest[j]+w[j][k]}

以下图为例


    earliest[0]=0

    earliest[1]=earliest[0]+w[0][1]=0+6=6

    earliest[2]=earliest[0]+w[0][2]=0+7=7

    earliest[4]=max{earliest[1]+w[1][4],earliest[2]+w[2][4]}=max{6+5,7+4}=11

    earliest[3]=max{earliest[1]+w[1][3],earliest[4]+w[4][3]}=max{6+3,11+3}=14

    earliest[5]=max{earliest[3]+w[3][5],earliest[4]+w[4][5]}=max{14+2,11+4}=16

    earliest[6]=earliest[4]+w[4][6]=11+3=14

  earliest[7]=max{earliest[3]+w[3][7],earliest[5]+w[5][7],earliest[6]+w[6][7]}=max{14+5,16+2,14+4}=19

最后得到的earliest[7]就是汇点的最早发生时间,从而可知这个工程至少需要19天完成。

事件的最迟发生时间与活动的最迟开始时间

    在不影响整个工程按时完成的前提下,一些事件可以不在最早发生时间发生,而向后推迟一段时间,事件最晚必须发生的时间称为该事件的最迟发生时间

    同样,有些活动可以推迟一段时间完成而不影响整个工程的完成,活动最晚必须开始的时间称为该活动的最迟开始时间

    一个事件在最迟发生时间内仍未发生,或一个活动在最迟开始时间内仍未开始,则必然会影响整个工程的按时完成。

    如图,事件Vj的最迟发生时间为所有直接后继事件Vjk(1<=k<=m)的最迟发生时间减去相应边<Vj,Vjk>上的权值(活动Ejk需要时间),取其中的最小值,且汇点的最迟发生时间就是他的最早发生时间,再按照逆拓扑顺序即可依次计算出所有事件的最迟发生时间。

设用数组lastest[1...n]表示所有事件的最迟发生时间,w[j][k]表示边<j,k>上的权值,且事件k是事件j的直接后继事件,则我们可按照逆拓扑顺序依次计算出lastest[k]:

    lastest[n]=n,lastest[j]=min{lastest[j]-w[j][k]}

以下图为例

    lastest[7]=earliest[7]=19

    lastest[6]=lastest[7]-w[6][7]=19-4=15

    lastest[5]=lastest[7]-w[5][7]=19-2=17

    lastest[3]=min{lastest[5]-w[3][5],lastest[7]-w[3][7]}=min{17-2,19-5}=14

    lastest[4]=min{lastest[3]-w[4][3],lastest[5]-w[4][5],lastest[6]-w[4][6]}=min{17-2,19-5,15-3}=11

    lastest[2]=lastest[4]-w[2][4]=11-4=7

    lastest[1]=min{lastest[3]-w[1][3],lastest[4]-w[1][4]}=min{14-3,11-5}=6

    lastest[0]=min{lastest[1]-w[0][1],lastest[2]-w[0][2]}=min{6-6,7-7}=0

开始时间余量与关键路径

    计算好每个事件的最早和最迟发生时间后,我们可以算出每个活动的最早和最迟开始时间。

    开始时间余量为一个活动的最迟开始时间减去最早开始时间。余量不等于0的活动表示该活动不一定要在最早开始时间时就进行,可以拖延一定的余量时间再进行,也不会影响整个工程的完成;余量等于0的活动必须在最早开始时间时进行,而且在规定的工期内完成,否则将影响整个工程的完成。

    我们将开始时间余量为0的活动称为关键活动,由关键活动所形成的从源点到汇点的每一条路径称为关键路径

    关键路径实质就是从源点到汇点具有最大路径长度的那些路径,因为整个工程的工期是按照最长路径计算的,显然,要缩短工期,应想方设法去缩短关键活动的持续时间。

    设用数组actearliest[1...n]表示所有活动的最早开始时间,actlastest[1...n]表示所有活动的最迟开始时间,w[j][k]表示边<j,k>上的权值,且活动i的两端事件分别是事件j与事件k,则:

    actearliest[i]=earliest[j],actlastest[i]=lastest[k]-w[j][k]

以下图为例


我们已从上述推导过程得知其每个事件的最早与最迟发生事件,因此可列出所有活动的最早与最迟开始时间以及时间开始余量。


由上表容易得出上图所示的AOE网的关键路径


阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u011815404/article/details/80316242
个人分类: 图论 数据结构
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

AOV网、拓扑排序以及关键路径

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭