求AOE网络中的关键路径算法
基于邻接矩阵存储的AOE网的关键路径算法的实现

F福建电脑UJIAN COMPUTER福建电脑2017年第11期1引言有向无环图在工程和管理中的应用有两种:AOV 网和AOE 网,前者用顶点表示活动,有向弧表示活动间。
后者用顶点表示事件,弧表示活动,弧上的权值表示活动持续的时间。
AOE 网在工程计划和管理中用于解决两类问题,一类是求解影响工程进度的关键活动,另一类是求解完成整个工程所需要的最少时间。
在AOE 网中唯一一个入度为零的顶点称作源点;唯一一个出度为零的顶点称作汇点。
从源点到汇点的最长路径称作关键路径,关键路径的长度就是完成整个工程任务所需要的最短时间。
关键路径上的活动都是关键活动。
如果这些活动中的任意一项未能按期完成,则整个工程就要延期。
如果某个关键活动的进度能够提前,那么整个工程就可能提前完成。
2算法所用数据结构:设图G =(V ,VR )是一个具有n 个顶点的有向网,其中,V 为顶点集,VR 为两个顶点间的关系的集合。
G 的邻接矩阵定义为如下n 伊n 矩阵A :则定义如下数组和矩阵:top_sort [n ]:存放G 的一个拓扑序列ve [n ]:ve [i ]为事件vi 的最早发生时间vl [i ]:vl [i ]为事件vi 的最晚发生时间e [n ][n ]:e [i ][j ]为活动<vi ,vj>的最早开始时间l [n ][n ]:l [i ][j ]为活动<vi ,vj>的最晚开始时间3基于邻接矩阵的拓扑排序(Topological Sort)的实现在顶点集V 和弧集E 构成的有向图G=(V ,E)中,满足如下条件的顶点序列(v i1,v i2,v i3…,v in )称为拓扑序列:对于序列中的任意两个顶点v i 、v j ,如果在G 中存在一条从v i 到v j 的路径,那么在序列中v i 一定在v j 之前。
如图1所示有向网的一个拓扑序列为:v 0,v 1,v 2,v 3,v 4,v 5,v 6,v 7,v 8。
AOE网的关键路径求解算法改进及其应用

3 2 1 图的存储结构 .. 图的存储 结构 采 用十 字 链表形 式 ,在 十 字链 表 , 中, 对应有 向图 中每一条弧有一个结 点 , 对应于每个顶
L i = L k 一D ti ) () V ( ) u (, k 求 、 () V () , i和 L 1需分两步进行 : E ()从 V () 0开始 向前递推 1 E1 =
A pe ehi e应用技术 4 pldTcn u i q 7
维普资讯
计 算 机 系 统 应 用
20 年 第 9 期 06
果工序 a 由弧 (, ) i ik 表示 , 其持续 时 间记 为 D t i ) u (, , k 则有如下关系 :
点也有一个结点 。这些结点的结构 如下 :
弧结点
Tie I H a vx l Hl l Tn I Io avx ede lk lk n l n i f
、 () , i=Ma {E i D ti }其 中 ( E xV ()+ u( ) i )∈T2 ,
≤i , 是所有以 i ≤n T 为头的弧的集合 。
关键 词 : 关键 路 径 A E网 生产 工序 O
1 引言
在项 目管理 中 , 合理 估计 工期 , 找出影响工 程进度 的关键活 动 , 从而采取各种措施 缩短 工期 , 提高 效率是 生产 管理 者的一 项核 心 工作。 而 A E网 的关键 路径 O 算法正是 用来解决此问题的。在传统的讲解数 据结构
刘小晶 ( 嘉兴 学院信 息工程 学院 34 0 ) 1 1 0
摘要 : 在项 目企业生产管理 中, 舍理估计工期是一个 必不可 少的环 节。而 A E网的关键路径 算法是 用 于此环 节的 O
关于AOE网中关键路径求解算法的研究

l 相关概念
在 A E网 中有 些活 动可 以并行 地进 行 , 以完 O 所
第三步 , A E网所有活动的最早开始时间 e 求 O 。
如 果活 动 a 由 < , 表 示 , 用公 式 ( ) 解 : () k> 利 3求
e i =v() ( ) ej () 3
V() M x v() d ti ) , 中 2<= ej = a { i + u(, }其 e <
=n () 1
第 二 步 , A E 网所 有 时 间 的最 迟 发 生 时 间 求 O v。利用 公式 ( ) v( )= v( ) l 2 从 ln e n 开始 向后递推 V()= n{f()一dti ) , 中 1< =i 1i Mi e u(, }其 <
第六步 , 找出所有 z e 0的关键路径。 —=
作者简 介 : 常友渠( 99一) 讲师 , 士学位 , 17 , 硕 主要研究方 向: 计算机应用 。
3 8
重 庆 电 力 高 等 专 科 学 校 学 报
第1 5卷
22 基于 P 阵的求解方法 . 矩
基于 P 矩阵的求关键路径的算法 : 第 一 步 , 造 图 G 的 /阶 P邻 接 矩 阵 M。 构 7 , = ( , o) 其中, 如果 邻接 v, , ( )>, j口 =< L i j 否则 0= 0的值 ; , 其中 L i 的值为 到 边上的权 ; () j 第 二步 , 据 构 造 : 根 将 中所 有 路删 去
【 关键词】 O A E网; 关键路径; 算法 ; 广度优先搜索遍历(F ) B S 【 中图分类号]P 1.2 T 311 【 文献标识码】 A 【 文章编号】08 02 2l) 1 O7 10— 3 (000 _ 3 3 8 o
(整理)AOE关键路径.

显然,对于关键活动而言,e(i)= l(i)。对于非关键活动,l(i)-e(i)的值是该工程的期限余量,在此范围内的适度延误不会影响整个工程的工期。
一个活动ai的最晚开始时间l(i)和最早开始时间e(i)的差值l(i)-e(i)是该活动完成的时间余量。它是在不增加完成整个工程所需的总时间的情况下,活动ai可以拖延的时间。当一活动的时间余量为零时,说明该活动必须如期完成,否则就会拖延整个工程的进度。所以称l(i)-e(i)=0,即l(i)=e(i)时的ai是关键活动。
(4)根据各顶点的ve和vl值,求每条弧(活动)ai的最早开始时间e(i)和最迟开始时间l(i)。
(5)找出e(i)=l(i)的活动,则为关键活动。由关键活动形成的由源点到汇点的每一条路径就是关键路径,关键路径有可能不止一条。
三、关键路径算法的实现
由于每个事件的最早发生时间ve(i)和vl(i)要在拓扑序列的基础上进行计算,所以关键路径算法的实现要基于拓扑排序算法,我们仍采用邻接表做有向图的存储结构。
if(vl[k]<vl[j]-p->weight) vl[k]= vl[j]-p->weight;
(6)从源点开始,对于每个顶点i,用指针p依次指向i的每个邻接顶点,取得每个顶点的序号j=p->adjvex,分别计算活动<vi,vj>的最早发生时间和最迟发生时间e和l。
e=ve[i];l=vl[j]-p->weight;
图6.22一个AOE网
和AOV-网不同,对AOE-网有待研究的问题是:
(1)完成整项工程至少需要多少时间?
(2)哪些活动是影响工程进度的关键?
由于在AOE-网中有些活动可以并行地进行,所以完成工程的最短时间是从开始点到完成点的最长路径的长度(这里所说的路径长度是指路径上各活动持续时间之和,不是路径上弧的数目)。路径长度最长的路径叫做关键路径(Critical Path)。假设开始点是v0,从v0到vi的最长路径长度叫做事件vi的最早发生时间。这个时间决定了所有以vi为尾的弧所表示的活动的最早开始时间。我们用e(i)表示活动ai的最早开始时间。还可以定义一个活动的最迟开始时间l(i),这是在不推迟整个工程完成的前提下,活动ai最迟必须开始进行的时间。两者之差l(i)-e(i)意味着完成活动ai的时间余量。我们把l(i)=e(i)的活动叫做关键活动。显然,关键路径上的所有活动都是关键活动,因此提前完成非关键活动并不能加快工程的进度。因此,分析关键路径的目的是辨别哪些是关键活动,以便争取提高关键活动的工效,缩短整个工期。
数据结构程序设计实验~AOE图的关键路径

数据结构课程设计报告专业网络工程班级姓名学号指导老师评分计算AOE网的关键路径AOE网即边表示活动的网络。
通常,可用AOE网来估算工程计划的完成时间。
如下所示的AOE网包括11项活动,9个事件,每个事件都有所需的完成时间。
我们现在要解决的是:(1)完成整项工程至少需要多少时间(最短时间);(2)哪些活动是影响工程进度的关键(关键活动)。
用e(i)表示活动最早开始时间,l(i)表示活动的最迟开始时间,则l(i)-e(i)为完成该活动的时间余量。
对于本例列表如下:下图就是上述AOE网的关键路径:请编程完成下列工作:1、输入:(1)顶点的信息和入度;(2)AOE网的边(始点、终点和权值)。
2、输出:(1) AOE网的邻接表(按“顶点入度:—>顶点权值”的格式输出)如a 0:-->4 5-->3 4-->2 6(2)输出关键活动每行所显示的分别为开始事件、结束事件、最早开始时间、最迟开始时间和完成活动的时间余量:当l(i)-e(i)=0时,在该行注明为关键活动。
如:a b 0 0 0 关键活动源程序#include<stdio.h>#include<stdlib.h>#include<iomanip.h>#include <process.h>//#define PROJECTNUMBER 9//10//#define PLANNUMBER 11//13typedef struct node{int adjvex;int dut;struct node *next;}edgenode;typedef struct{int projectname;int id;edgenode *link;}vexnode;//vexnode Graphicmap[PROJECTNUMBER];void CreateGraphic(vexnode* Graphicmap,int projectnumber,int activenumber){int begin,end,duttem;edgenode *p;for(int i=0;i<projectnumber;i++){Graphicmap[i].projectname=i;Graphicmap[i].id =0;Graphicmap[i].link =NULL;}printf("某项目的开始到结束在图中的节点输入<vi,vj,dut>\n");printf("如:3,4,9 回车表示第三节点到第四节点之间的活动用了9个单位时间\n"); for(int k=0;k<activenumber;k++){scanf("%d,%d,%d",&begin,&end,&duttem);p=(edgenode*)malloc(sizeof(edgenode));p->adjvex =end-1;p->dut =duttem;Graphicmap[end-1].id ++;p->next =Graphicmap[begin-1].link ;Graphicmap[begin-1].link =p;}}int SearchMapPath(vexnode* Graphicmap,int projectnumber,int activenumber,int& totaltime){int i,j,k,m=0;int front=-1,rear=-1;int* topologystack=(int*)malloc(projectnumber*sizeof(int));//用来保存拓扑排列int* vl=(int*)malloc(projectnumber*sizeof(int));//用来表示在不推迟整个工程的前提下,VJ允许最迟发生的时间int* ve=(int*)malloc(projectnumber*sizeof(int));//用来表示Vj最早发生时间int* l=(int*)malloc(activenumber*sizeof(int));//用来表示活动Ai最迟完成开始时间 int* e=(int*)malloc(activenumber*sizeof(int));//表示活动最早开始时间edgenode *p;totaltime=0;for(i=0;i<projectnumber;i++) ve[i]=0;for(i=0;i<projectnumber;i++){if(Graphicmap[i].id==0){topologystack[++rear]=i;m++;}}while(front!=rear){front++;j=topologystack[front];m++;p=Graphicmap[j].link ;while(p){k=p->adjvex ;Graphicmap[k].id --;if(ve[j]+p->dut >ve[k])ve[k]=ve[j]+p->dut ;if(Graphicmap[k].id ==0)topologystack[++rear]=k;p=p->next ;}}if(m<projectnumber){printf("\n本程序所建立的图有回路不可计算出关键路径\n");printf("将退出本程序\n");return 0;}totaltime=ve[projectnumber-1];for(i=0;i<projectnumber;i++)vl[i]=totaltime;for(i=projectnumber-2;i>=0;i--){j=topologystack[i];p=Graphicmap[j].link ;while(p){k=p->adjvex ;if((vl[k]-p->dut )<vl[j])vl[j]=vl[k]-p->dut ;p=p->next ;}}i=0;printf("| 起点 | 终点 | 最早开始时间 | 最迟完成时间 | 差值 | 备注 |\n");for(j=0;j<projectnumber;j++){p=Graphicmap[j].link;while(p){k=p->adjvex ;e[++i]=ve[j];l[i]=vl[k]-p->dut;printf("| %4d | %4d | %4d | %4d | %4d |",Graphic map[j].projectname +1,Graphicmap[k].projectname +1,e[i],l[i],l[i]-e[i]);if(l[i]==e[i])printf(" 关键活动 |");printf("\n");p=p->next ;}}return 1;}void seekkeyroot(){int projectnumber,activenumber,totaltime=0;system("cls");printf("请输入这个工程的化成图形的节点数:");scanf("%d",&projectnumber);printf("请输入这个工程的活动个数:");scanf("%d",&activenumber);vexnode* Graphicmap=(vexnode*)malloc(projectnumber*sizeof(vexnode)); CreateGraphic(Graphicmap,projectnumber,activenumber);SearchMapPath(Graphicmap,projectnumber,activenumber,totaltime);printf("整个工程所用的最短时间为:%d个单位时间\n",totaltime);system("pause");}int main(){char ch;for(;;){do{system("cls");printf("| 欢迎进入求关键路径算法程序 |");for(int i=0;i<80;i++)printf("*");printf("%s","(S)tart开始输入工程的节点数据并求出关键路径\n"); printf("%s","(E)xit退出\n");printf("%s","请输入选择:");scanf("%c",&ch);ch=toupper(ch);}while(ch!='S'&&ch!='E');switch(ch){case'S':seekkeyroot(); break; case'E':return 1; }}}。
关键路径算法

(4)根据各顶点的ve和vl值,求每条弧s的最早开 始时间e(s)和最迟开始时间 l(s)。若某条弧满足条 件e(s)=l(s),则为关键活动。
先将拓扑排序算法7.12改写成算法7.13,则算法 7.14便为求关键路径的算法。
typedef float AdjType;
typedef struct ArcNode
{ int adjvex;
/* 相邻顶点字段 */
AdjType weight; struBiblioteka t ArcNode *nextarc;
/* 链字段 */
}ArcNode;
/* 边表中的结点 */
&top)
{ int k;
while(p)
/* 删除以该顶点为起点的边 */
{ k=p->adjvex;
indegree[k]--;
if(indegree[k]==0) /* 将新的入度为零的边 入栈 */
{ indegree[k]=top;
top=k;
}
p=p->nextarc;
p=p->nextarc;
}
}
}
void countvl(ALGraph G,int *topo,AdjType *ve, AdjType *vl) /* 计算各事件的最迟发生时间*/
{ int i,j,k; ArcNode *p; for(i=0;i<G.vexnum;i++) //求事件vi允许的最迟发生时间vl(i) vl[i]=ve[G.vexnum-1]; /*每个事件的最迟发生时间赋初值
关键路径AOE网及其如何求关键路径步骤

关键路径AOE网及其如何求关键路径步骤一、关键路径(一)AOE网在带权有向图中,以顶点表示事件,以有向边表示活动,以边上的权值表示完成该活动的开销(如完成活动所需的时间),称之为用边表示活动的网络,简称AOE网(Activity On Edge NetWork)AOE⽹具有以下两个性质:①只有在某顶点所代表的事件发生后,从该顶点出发的各有向边所代表的活动才能开始;②只有在进入某顶点的各有向边所代表的活动都已结束时,该顶点所代表的事件才能发生。
另外,有些活动是可以并行进行的在AOE网中仅有一个入度为0的顶点,称为开始顶点(源点),它表示整个工程的开始;也仅有一个出度为0的顶点,称为结束顶点(汇点),它表示整个工程的结束。
(二)关键路径从源点到汇点的有向路径可能有多条,所有路径中,具有最大路径长度的路径称为关键路径,⽽把关键路径上的活动称为关键活动完成整个工程的最短时间就是关键路径的长度,若关键活动不能按时完成,则整个工程的完成时间就会延迟。
活动ai的时间余量d(i)=l(i)-e(i),表⽰在不增加完成整个工程所需总时间的情况下,活动ai 可以拖延的时间若一个活动的时间余量为零,则说明该活动必须要如期完成,d(i)=0即l(i)=e(i)的活动ai是关键活动由关键活动组成的路径就是关键路径(三)求关键路径的步骤(四)求所有事件的最早发生时间1.求所有事件的最早发生时间ve()(五)求所有事件的最迟发生时间1.求所有事件的最迟发生时间vl()1.求所有活动的最早发生时间e()1.求所有活动的最迟发生时间l()(八)求所有活动的时间余量(九)关键活动、关键路径的特性若关键活动耗时增加,则整个工程的工期将增长缩短关键活动的时间,可以缩短整个工程的工期当缩短到一定程度时,关键活动可能会变成非关键活动可能有多条关键路径,只提高⼀条关键路径上的关键活动速度并不能缩短整个工程的工期,只有加快那些包括在所有关键路径上的关键活动才能达到缩短工期的目的。
AOE网中求取关键路径的一种新算法

图1
图2
结点
v1 v2 v3 v4 v5 v6 v7 v8 S
表1 从 v 到各结点最短路径的求解过程
0
i =1 3 7 5 ∪ { v1 }
得出源点到汇点的最短路径长度为 16, 通过回溯 前驱结点分别记录两条路径 v → v → v → v → v 和 此两条路径即为所有原 AOE v →v →v →v →v ; 网的关键路径, 如图 3, 每条路径都穿程 4 条边, 所以 关键路径长度为 e·W - D = 4·9 - 16 = 20 。这里特 别需要指出, 正常情况下, 汇点的最短路径一定是所 有算得结点最短路径长度中的极大值。如果汇点的 最短路径不是在最后一次循环计算得出或者不是所 有结点最短路径长度中的极大值的话, 则说明该 AOE 网存在异常, 并非一个合理工程施工的进度表述。
谢㊀ 科㊀ 丁皓明㊀
㊀ AOE
网中求取关键路径的一种新算法
AOE
网中求取关键路径的一种新算法
谢㊀ 科, 丁皓明
( 阿坝师范学院㊀ 数学与计算机科学学院,四川㊀ 汶川㊀
623002
)
摘要: 基于求解单源最短路径问题的 Dijkstra 算法, 提出在 AOE 网络中求取关键路径的一种新算法。该算法易 于理解, 适合在“数据结构与算法”课程教学改革中使用。 ㊀ ㊀ 关键词: AOE 网; 最短路径; 关键路径; 教学改革 ㊀ ㊀ 中图分类号: TP393㊀ ㊀ 文献标识码: A㊀ ㊀ 文章编号: 2096 - 1707 ( 2017 ) 03 - 0121 - 02
㊀ ㊀
S ∪ { vj } 3 V - S ( min D [ k ] D [ j ] + v j v k ) 4 2 3
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
//求AOE网络中的关键路径算法
#include <cstdio>
#include <cstring>
#define MAXN 100 //顶点个数的最大值
#define MAXM 200 //边数的最大值
struct ArcNode
{
int to, dur, no; //边的另一个顶点,持续时间,活动序号
ArcNode *next;
};
int n, m; //顶点个数、边数
ArcNode* List1[MAXN]; //每个顶点的边链表表头指针(出边表) ArcNode* List2[MAXN]; //每个顶点的边链表表头指针(入边表) int count1[MAXN]; //各顶点的入度
int count2[MAXN]; //各顶点的出度
int Ee[MAXN]; //各事件的最早可能开始时间
int El[MAXN]; //各事件的最迟允许开始时间
int e[MAXM]; //各活动的最早可能开始时间
int L[MAXM]; //各活动的最迟允许开始时间
void CriticalPath( ) //求关键路径
{
//拓扑排序求Ee
int i, j, k;
int top1 = -1;
ArcNode* temp1;
memset( Ee, 0, sizeof(Ee) );
for( i=0; i<n; i++ )
{
if( count1[i]==0 )
count1[i] = top1, top1 = i;
}
for( i=0; i<n; i++ )
{
if( top1==-1 )
{
printf( "Network has a cycle!\n" ); return;
}
else
{
j = top1; top1 = count1[top1];
temp1 = List1[j];
while( temp1!=NULL )
{
k = temp1->to;
if( --count1[k]==0 )
count1[k] = top1, top1 = k;
if( Ee[j] + temp1->dur > Ee[k] ) //有向边<j,k> Ee[k] = Ee[j] + temp1->dur;
temp1 = temp1->next;
}//end of while
}//end of else
}//end of for
//逆拓扑排序求El
int top2 = -1;
ArcNode* temp2;
for( i=0; i<n; i++ )
{
El[i] = Ee[n-1];
if( count2[i]==0 )
count2[i] = top2, top2 = i;
}
for( i=0; i<n; i++ )
{
j = top2; top2 = count2[top2];
temp2 = List2[j];
while( temp2!=NULL )
{
k = temp2->to;
if( --count2[k]==0 )
count2[k] = top2, top2 = k;
if( El[j] - temp2->dur < El[k] ) //有向边<k,j> El[k] = El[j] - temp2->dur;
temp2 = temp2->next;
}//end of while
}//end of for
//求各活动的e[k]和L[k]
memset( e, 0, sizeof(e) ); memset( L, 0, sizeof(L) ); printf( "The critical activities are:\n" );
for( i=0; i<n; i++ ) //释放边链表上各边结点所占用的存储空间{
temp1 = List1[i];;
while( temp1!=NULL )
j = temp1->to; k=temp1->no; //有向边<i,j>
e[k] = Ee[i]; L[k] = El[j] - temp1->dur;
if( e[k]==L[k] )
printf( "A%d : %d->%d\n", k, i, j );
temp1 = temp1->next;
}
}
}
int main( )
{
int i, u, v, w; //循环变量、边的起点和终点
scanf( "%d%d", &n, &m ); //读入顶点个数n,边数
memset( List1, 0, sizeof(List1) ); memset( List2, 0, sizeof(List2) );
memset( count1, 0, sizeof(count1) ); memset( count2, 0, sizeof(count2) );
ArcNode *temp1, *temp2;
for( i=0; i<m; i++ )
{
scanf( "%d%d%d", &u, &v, &w ); //读入边的起点和终点
count1[v]++;
temp1 = new ArcNode; //构造邻接表
temp1->to = v; temp1->dur = w;
temp1->no = i+1; temp1->next = NULL;
if( List1[u]==NULL ) List1[u] = temp1;
else{ temp1->next = List1[u]; List1[u] = temp1; }
count2[u]++;
temp2 = new ArcNode; //构造邻接表
temp2->to = u; temp2->dur = w;
temp2->no = i+1; temp2->next = NULL;
if( List2[v]==NULL ) List2[v] = temp2;
else{ temp2->next = List2[v]; List2[v] = temp2; } }
CriticalPath( );
for( i=0; i<n; i++ ) //释放边链表上各边结点所占用的存储空间
{
temp1 = List1[i]; temp2 = List2[i];
while( temp1!=NULL )
{
List1[i] = temp1->next; delete temp1; temp1 = List1[i];
}
while( temp2!=NULL )
List2[i] = temp2->next; delete temp2; temp2 = List2[i];
}
}
return 0;
}
代码来自。