AOE网与关键路径

如果在有向图中用顶点表示事件,用弧表示活动,用弧上的权表示活动持续时间,称该带权有向图(即有向网)为边表示活动的网(activity on edge network),简称AOE网。

在AOE网中,只有一个顶点代表的事件发生后,从该顶点出发的各个弧所代表的活动才能开始,只有以弧头关联一个顶点的各个弧所代表的活动都已结束,该顶点所代表的事件才能发生。

一项工程可以由若干个子工程活动组成。用AOV网表示这项工程所关心的是各子工程之间的优先次序,即所得到得拓扑有序序列;而用AOE网表示这项工程所关心的是完成整个工程至少需要多少时间,哪些子工程是影响这项工程进度的关键活动,如何加快整个工程的进度等问题。

由于在AOE网中某些活动可以并行进行,所以完成工程的最短时间是从源点到汇点路径的最大长度(指路径上各活动持续时间之和最大,而不是路径上弧的数目最多)。把从源点到汇点路径长度最大的路径称作关键路径(critical path),关键路径上的活动称作关键活动。关键活动的长度是整个工程的最短工期,加快关键活动的完成是加快工程进度缩短工期地关键。

求AOE网关键路径算法的步骤:

(1).输入e条弧<Vj,Vk>,建立AOE网的存储结构。

(2).从源点V1出发,令ve[1]=0;按拓扑有序序列次序求其余各顶点的最早发生时间ve[k](2<=k<=n),ve[k]=max{ve[j]+dut(<Vj,Vk>)};如果得到的拓扑有序序列中顶点个数小于网中顶点的个数n,说明网中存在环路,不能求关键路径算法终止,否则执行步骤(3).

(3).从汇点Vn出发,令vl[n]=ve[n],按逆拓扑有序序列求其余各顶点的最迟发生时间vl[k](n-1>=k>=1),vl[k]=min{vl[Vj]-dut(<Vk-Vj>)}。

(4).根据各顶点的ve值和vl值,求每条弧的最早开始时间e[s]和最迟开始时间l[s];e[s]等于弧s的弧尾顶点Vk的最早发生时间ve[k],而l[s]等于弧头顶点Vk的最迟发生时间减去弧s的权值;若某条弧s满足e[s]=l[s]则为关键活动,由所有关键活动构成的网的一条或几条关键路径。


int toporder(adjlist g[],int n,sqstack t)//AOE网用带入度域的邻接表g[]存储,算法求n个顶点的最早发生时间ve[](全局变量)
//并在顺序栈t中记录顶点的拓扑有序序列
{
    int i,j,k,m=0,top=0;//定义局部变量并初始化统计变量和链栈指针
    nodetype *p;//定义指向邻接表表结点的指针变量
    for(i=1;i<=n;i++) ve[i]=0;//初始化ve[]
    for(i=1;i<=n;i++)//把入度为0的顶点压入由入度域建立的链栈中
        if(g[i].indegree==0)
        {
            g[i].indegree=top;
            top=i;
        }
    while(top!=0)//当链栈不为空时,拓扑排序过程中计算ve[],并在栈t中记下拓扑序列
    {
        j=top;
        top=g[top].indegree;
        push(t,j);//顶点Vj的序号压入顺序栈t中
        m++;//统计变量m加1
        p=g[j].next;//p指向邻接链表第j个链表的第一个结点
        while(p!=NULL)//处理第j个链表中各顶点
        {
            k=p->adjvex;//k指向表结点
            g[k].indegree--;//第k个顶点的入度减1
            if(g[k].indegree==0)//如果入度为0则压入栈中
            {
                g[k].indegree=top;//Vk的入度域指向原栈顶
                top=k;//栈顶指向Vk
            }
            if(ve[j]+p->data>ve[k])//计算ve[k]
                ve[k]=ve[j]+p->data;
            p=p->next;//p指向第j个链的下一个邻接顶点
        }
    }
    if(m<n)//如果m<n有环路,返回0否则返回1
        return 0;
    else 
        return 1;
}


void criticalpath(adjlist g[],int n)//g[]为带权邻接链表存储的AOE网,n为顶点数,算法输出关键路径上各关键活动
{
    int i,j,k,e,l,dut;//定义局部变量
    sqstack t;//定义顺序栈t
    if(toporder(g,n,t)==0)//如果toporder值为0,打印AOE网有环路
        printf("the AOE network has a cycle\n");
    else//否则无环,计算vl值并求e和l确定活动关键
    {
        for(i=n;i>=1;i--)//初始化vl[]
            vl[i]=ve[n];
        while(empty(t)!=0)//当顺序栈不空时,逐一弹出栈顶元素计算vl[j]
        {
            j=pop(t);//弹出栈顶元素于j
            p=g[j].next;//p指向邻接表中第j个链表
            while(p!=NULL)//当链不空时
            {
                k=p->adjvex;//k指向表结点
                dut=p->data;//弧的权值送dut
                if(vl[k]-dut<vl[j])//计算vl[j]
                    vl[j]=vl[k]-dut;
                p=p->next;//p指向第j个链表的下一个邻接点
            }
        }
        for(j=1;j<=n;j++)//求e,l和关键活动
        {
            p=g[j].next;//p指向邻接表中第j个链表的第一个结点
            while(p!=NULL)//处理Vj与第j个链表中各顶点组成的弧
            {
                 k=p->adjvex;//链中顶点的序号送k
                 dut=p->data;//弧<Vj,Vk>的权值送dut中
                 e=ve[j];//e为Vj的最早发生时间
                 l=vl[k]-dut;//l为Vk的最迟发生时间减去弧<Vj,Vk>和权值
                 if(e==l)
                     printf("v%d to v%d:weight is %d\n",j,k,dut);
                p=p->next;//p指向第j个链表的下一个顶点
            }
        }
    }
}//criticalpath end


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
西南交大;西南交通大学;数据结构;赵宏宇;一、二叉树(二) 1. 写算法 (1) 二叉树的直径定义为从根结点至叶子的最大路径长度。编写算法,求二叉树(二叉链表)的直径。 (2) 已知二叉树(二叉链表)根结点指针bt,树中两个结点的指针p、q。编写算法求距离结点*p和*q最近的公共祖先的地址。 (3) 已知二叉树(二叉链表)根结点指针bt,利用二叉树叶子结点的rchild指针域将所有叶子结点从左向右连接成一个单向链表。算法返回单向链表头结点指针(即最左边第1个叶子结点的地址)。 2. 编程题 (1) 从键盘输入一个字符串(要求字符串中无重复字符),将串中字符当做完全二叉树的顺序存储结构,建立对应的完全二叉树的二叉链表存储结构,输出先、中、后序遍历结果。 (2) 用先序遍历法建立二叉树二叉链表存储结构(结点数据域类型为char,输入字符序列用字符'#'表示NULL),实现中序线索化,并用非递归算法输出中序遍历结果的正序和逆序序列。 二、图 1. 已知某无向图如下图所示。画出该图的多重邻接表存储结构示意图。根据该存储结构,写出从顶点v0出发,深度和宽度优先遍历顶点访问次序。 2. 写一个算法,判断无向图是否有环。算法提要:深度优先遍历过程中,访问某顶点后,该顶点的邻接点中有已访问的顶点且该已访问邻接点不是该顶点的上一级递归出发顶点(即存在回边),则有环。 3. 编程题: 建立无向图邻接表存储结构,输出深度和宽度优先遍历顶点访问次序。 4. 编程题:建立AOE络存储结构,计算并输出ve[]和vl[]。 5. 选作题*:算法设计-已知AOE络的邻接表存储结构G,ve[]和vl[]值已全部求取,写出算法,输出所有关键路径。要求每条关键路径用源点至汇点的顶点序列(拓扑有序)表示。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值