实现求关键路径的算法
一种求解关键路径的新算法

( p.f ot r n ier g S ez e oyeh i, hn h n5 8 5 ) De to f eE gn e n , hn hnP ltc ncS e ze 1 0 5 S wa i
[ s a t n w ag rh fr n igtec t a pts s rp sdb s gc ̄n rp n toto oo i l otB xedn edt Ab t c]A e loi m dn r cl a o oe yu i o gga ha dwi u p lgc r yetn gt aa r t of i h i i h ip n h t as . i h
[ yw r s o igga h cicl ah ; t i nE g ( E nt ok bed —rte c ;i o lxt Ke d eAO ) ew r ;rat f ssa h t c mpe i i i y hi r me y
adn e ses trg aeTh me o lxt )whc we a ( o et dt n g rh n ed s s aes c. e i mpe i i D( l o p t c ys , i hil r nO n) f aio a a o tm. so t h h t r i ll i
h e g f m e t t t eln t o d siain o et o r en d . mp e t eta i o a g rt ms teag rtm rpo e ssmpe,moeu d rtn a l hr n o n d o s uc o e Co a d wi t dt n a o i r h h r i l l h , o h p o sd i i lr h l i r n e sa d be
第20讲-关键路径与最短路径

数据结构第20次课(续表)思考.题作业题试对下图所示的AOE网络,解答下列问题。
(1) 这个工程最早可能在什么时间结束。
(2) 求每个事件的最早开始时间Ve[i]和最迟开始时间Vl[I]。
(3) 求每个活动的最早开始时间e( )和最迟开始时间l( )。
(4) 确定哪些活动是关键活动。
画出由所有关键活动构成的图,指出哪些活动加速可使整个工程提前完成。
*参考资料《数据结构辅导与提高》,徐孝凯编著,清华大学出版社《数据结构习题解答与考试指导》,梁作娟等编著,清华大学出版社授课内容关键路径对整个工程和系统,人们关心的是两个方面的问题:一)工程能否顺利进行(对AOV网进行拓扑排序)二)估算整个工程的完成所必须的最短时间(对AOE网求关键路径)1. AOE-网}与AOV-网相对应的是AOE-网(Activity On Edge),即边表示活动的网。
AOE-网是一个带权的有向无环图,其中,顶点表示事件(Event),弧表示活动,权表示活动持续的时间。
通常,AOE-网可用来估算工程的完成时间。
例:下图是一个假想的有11项活动的AOE-网。
其中有9个事件v1,v2,…,v9,每个事件表示在它之前的活动已经完成,在它之后的活动可以开始。
如v1表示整个工程开始,v9表示整个工程结束,v5表示a4和a5已经完成,a7和a8可以开始。
与每个活动相联系的数是执行该活动所需的时间。
比如,活动a1需要6天,a2需要4天等。
和AOV-网不同,对AOE-网有待研究的问题是:(1)完成整项工程至少需要多少时间(2)哪些活动是影响工程进度的关键2. 关键路径由于在AOE-网中有些活动可以并行地进行,所以完成工程的最短时间是从开始点到完成点的最长路径的长度(这里所说的路径长度是指路径上各活动持续时间之和,不是路径上弧的数目)。
路径长度最长的路径叫做关备注:回顾键路径(Critical Path)。
假设开始点是v1,从v1到v i的最长路径长度叫做事件v i的最早发生时间。
离散数学最短路径和关键路径

*
1
关键路径(续)
vi的缓冲时间TS(vi)=TL(vi)-TE(vi), i=1,2,,n vi在关键路径上TS(vi)=0
*
例2 求PERT图中各顶点的最早完成时间, 最晚完成
时间, 缓冲时间及关键路径.
解 最早完成时间
TE(v1)=0
TE(v2)=max{0+1}=1
TE(v3)=max{0+2,1+0}=2
设带权图G=<V,E,w>, 其中eE, w(e)0. 设V={v1,v2,,vn}, 求v1到其余各顶点的最短路径 p标号(永久性标号) : 第r步获得的v1到vi最短路径的 权 t标号(临时性标号) : 第r步获得的v1经过p标号顶点 到达vi的路径的最小权, 是v1到vi的最短路径的权的上 界 第r步通过集Pr={v | v在第r步已获得永久性标号} 第r步未通过集Tr=V-Pr
*
带权图G=<V,E,w>, 其中w:ER. eE, w(e)称作e的权. e=(vi,vj), 记w(e)=wij . 若vi,vj不 相邻, 记wij =. 设L是G中的一条路径, L的所有边的权之和称作L的 权, 记作w(L). u和v之间的最短路径: u和v之间权最小的通路.
标号法(, 1959)
*
标号法(续)
例1(续) 求v0到v5的最短路径 v0 v1 v2 v3 v4 v5 0 0 1 4 1 1/v0 3 8 6 2 3/v1 8 4 3 7 4/v2 10 4 7/v4 9 5 9/v3 w 0 1 3 7 4 9 =v0v1v2v4v3v5, w()=9
*
关键路径
vi的最早完成时间TE(vi): 从始点v1沿最长路径到vi
数据结构的应用的拓扑排序与关键路径算法

数据结构的应用的拓扑排序与关键路径算法拓扑排序与关键路径算法是数据结构中重要的应用之一。
拓扑排序通过对有向图的节点进行排序,使得对于任意一条有向边(u,v),节点 u 在排序中都出现在节点 v 之前。
关键路径算法则是用来确定一个项目的关键活动和最短完成时间。
拓扑排序的实现可以通过深度优先搜索或者广度优先搜索来完成。
深度优先搜索是递归地访问节点的所有未访问过的邻居节点,直到没有未访问过的邻居节点为止,然后将该节点添加到拓扑排序的结果中。
广度优先搜索则是通过使用队列来实现的,将节点的邻居节点逐个入队并进行访问,直到队列为空为止。
无论使用哪种方法,拓扑排序都可以通过判断节点的入度来进行。
拓扑排序在很多实际问题中都有广泛应用。
比如在任务调度中,拓扑排序可以用来确定任务间的依赖关系和执行顺序;在编译原理中,拓扑排序可以用来确定程序中变量的定义和使用顺序。
关键路径算法用于确定项目中的关键活动和最短完成时间。
它通过计算每个活动的最早开始时间和最晚开始时间,以及每个活动的最早完成时间和最晚完成时间来实现。
具体步骤如下:1. 构建有向加权图,其中节点表示项目的活动,有向边表示活动间的先后关系,边的权重表示活动的持续时间。
2. 进行拓扑排序,确定活动的执行顺序。
3. 计算每个活动的最早开始时间,即从起始节点到该节点的最长路径。
4. 计算每个活动的最晚开始时间,即从终止节点到该节点的最长路径。
5. 根据每个活动的最早开始时间和最晚开始时间,可以确定关键活动,即最早开始时间与最晚开始时间相等的活动。
6. 计算整个项目的最短完成时间,即从起始节点到终止节点的最长路径。
拓扑排序与关键路径算法在工程管理、任务调度、生产流程优化等领域都有重要应用。
它们能够帮助我们有效地组织和管理复杂的项目,提高工作效率和资源利用率。
在实际应用中,我们可以借助计算机编程以及各种图算法库来实现这些算法,从而更快速、准确地解决实际问题。
综上所述,拓扑排序与关键路径算法是数据结构的重要应用之一。
关键路径法

关键路径法关键路径法(Critical Path Method, CPM)是借助网络图和各活动所需时间(估计值),计算每一活动的最早或最迟开始和结束时间。
CPM法的关键是计算总时差,这样可决定哪一活动有最小时间弹性。
CPM算法的核心思想是将WBS分解的活动按逻辑关系加以整合,统筹计算出整个项目的工期和关键路径。
1.关键路径因网络图中的某些活动可以并行地进行,所以完成工程的最少时间是从开始节点到结束节点的最长路径长度,称从开始节点到结束节点的最长路径为关键路径(临界路径),关键路径上的活动为关键活动。
有关关键路径的具体求法,请阅读8.1.3节。
2.时差一般来说,不在关键路径上的活动时间的缩短,不能缩短整个工期。
而不在关键路径上的活动时间的延长,可能导致关键路径的变化,因此可能影响整个工期。
活动的总时差是指在不延误总工期的前提下,该活动的机动时间。
活动的总时差等于该活动最迟完成时间与最早完成时间之差,或该活动最迟开始时间与最早开始时间之差。
活动的自由时差是指在不影响紧后活动的最早开始时间前提下,该活动的机动时间。
活动自由时差的计算应按以下两种情况分别考虑:(1)对于有紧后活动的活动,其自由时差等于所有紧后活动最早开始时间减本活动最早完成时间所得之差的最小值。
例如,假设活动A的最早完成时间为4,活动A有两项紧后活动,其最早开始时间分别为5和7,则A的自由时差为1。
(2)对于没有紧后活动的活动,也就是以网络计划终点节点为完成节点的活动,其自由时差等于计划工期与本活动最早完成时间之差。
需要指出的是,对于网络计划中以终点节点为完成节点的活动,其自由时差与总时差相等。
此外,由于活动的自由时差是其总时差的构成部分,所以,当活动的总时差为0时,其自由时差必然为0,可不必进行专门计算。
3.费用斜率一项活动所用的时间可以有标准所需时间S和特急所需时间E,对应的费用分别为SC和EC,则活动的费用斜率的计算公式如下:C=(EC-SC)/(S-E)由上述公式,我们可以发现,费用斜率描述的是某一项活动加急所需要的代价比,即平均每加急一个时间单位所需要付出的代价。
项目管理的关键路径公式

项目管理的关键路径公式
项目管理的关键路径(Critical Path)是项目计划中耗时最长、对项目总时间影响最大的路径,它决定了项目的总持续时间。
关键路径的确定主要基于以下公式:
1. 任务持续时间:每个任务都有一个预计的完成时间。
这是从任务开始到结束所需的总时间。
2. 任务之间的逻辑关系:任务之间可能存在先后关系,这决定了任务执行的顺序。
这些逻辑关系可以用“AND”或“OR”关系表示。
3. 计算路径的总时间:对于每条路径(即一系列任务的执行顺序),需要计算其总时间。
这可以通过将路径上所有任务的时间相加来完成。
4. 确定关键路径:具有最长总时间的路径是关键路径。
关键路径上的任何延迟都会直接影响项目的总完成时间。
在实际的项目管理软件中,例如Microsoft Project,这些计算通常是自动完成的,项目经理只需要输入每个任务的时间和它们之间的逻辑关系,软件就会自动找出关键路径。
然而,如果你需要手动计算,你通常会使用表格或电子表格程序(如Excel)来列出所有任务和它们的时间,然后通过逻辑关系和简单的数学运算(加法)来找出关键路径。
关键路径法(中文)

关键路径法关键路径法是使用最广的计划编制方法,也被称为关键路径计划。
这种方法能推算出项目的最短完成时间和项目各项活动的可能开始和结束时间。
确实,很多教材和管理人员把关键路径法看作最实用的计划编制程序。
关键路径法的计算机程序和运算法则已经被广泛应用,可以有效地处理包含数千活动的项目。
关键路径本身代表了一系列前继后续的活动,这些活动将会持续最长的时间,关键路径的持续时间等于关键线路上全部活动持续时间的总和。
因此,关键路径就像在第九章描述的那样,被定义为项目活动网络中最长的可能路径。
关键路径的时间就代表了完成项目所需的最短时间。
关键路径上的任何活动推迟都将导致项目完成时间的增加。
在全部的项目活动中,可能会有多条关键路径。
所以,整个工程的完成时间会因任何一条关键路径上活动的推迟而延后。
例如,一个项目有两个并列进行活动组成,每个活动都需3天完成,那么就要求每个关键工作在3天内完成。
关键路径法在形式上假设项目已被分成具有固定持续时间和明确前后顺序关系的活动。
前后顺序关系在计划中意味着一个活动必须在另一个活动前开始。
除了这种时间上前后顺序关系外,没有资源限制的关键路径计划被认为是最简单的形式。
在实际运用关键路径法时,工程计划者经常通过优先关系描述资源的限制。
限制是对管理人员可能选择的一种约束,资源的限制来源于有限的可用资源,如设备、材料、空间或劳动力。
例如,如果两个活动需要同样的设备,就可能假设任意一个活动优先于另一个。
人为划分的优先限制确保两个需要同一资源的活动不被安排在同一时间。
大部分关键路径的运算方法也利用了活动关系或所使用的网络几何学原则加以限制。
这些限制条件表明,工程计划能够用网络计划法表示。
在网络计划中,用两个节点表示活动,节点要进行编号,两个节点不能用相同的号码,引入的两个节点表示一项工作的起始和终止。
工程进度计划的现行计算机表示法一般由一张表示工作以及这些工作相应的持续时间、所需的资源和紧前工作等内容的一览表组成。
关键路径算法

关键路径算法相关概念: (1)AOE (Activity On Edges)⽹络如果在⽆有向环的带权有向图中⽤有向边表⽰⼀个⼯程中的各项活动(Activity),⽤边上的权值表⽰活动的持续时间(Duration),⽤顶点表⽰事件(Event),则这样的有向图叫做⽤边表⽰活动的⽹络,简称AOE (Activity On Edges)⽹络。
AOE ⽹是⼀个带权的有向⽆环图。
AOE⽹络在某些⼯程估算⽅⾯⾮常有⽤。
例如,可以使⼈们了解: a、完成整个⼯程⾄少需要多少时间(假设⽹络中没有环)? b、为缩短完成⼯程所需的时间, 应当加快哪些活动? (2)关键路径(Critical Path) 在AOE⽹络中, 有些活动顺序进⾏,有些活动并⾏进⾏。
从源点到各个顶点,以⾄从源点到汇点的有向路径可能不⽌⼀条。
这些路径的长度也可能不同。
完成不同路径的活动所需的时间虽然不同,但只有各条路径上所有活动都完成了,整个⼯程才算完成。
因此,完成整个⼯程所需的时间取决于从源点到汇点的最长路径长度,即在这条路径上所有活动的持续时间之和。
这条路径长度最长的路径就叫做关键路径(Critical Path)。
(3)由于实际⼯程只有⼀个开始点和⼀个结束点,因此AOE⽹存在唯⼀的⼊度为0的开始点(⼜称源点)和唯⼀的出度为0的结束点(⼜称汇点)参数定义: (1)事件的最早发⽣时间 etv(earliest time of vertex):即顶点V k的最早发⽣时间。
(2)事件的最晚发⽣时间 ltv(latest time of vertex):即顶点V k的最晚发⽣时间,也就是每个顶点对应的事件最晚需要开始的时间,超出此事件将会延误整个⼯期。
(3)活动的最早开⼯时间 ete(earliest time of edge):即弧ak的最早发⽣时间。
(4)活动的最晚开⼯时间 lte(latest time of edge):即弧ak的最晚发⽣时间,也就是不推迟⼯期的最晚开⼯时间。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
沈阳航空航天大学课程设计报告课程设计名称:数据结构课程设计课程设计题目:实现求关键路径的算法院(系):计算机学院专业:计算机科学与技术班级:04010102学号:*******************指导教师:***完成日期:2014年1月9日沈阳航空航天大学课程设计报告目录第一章需求分析 (1)1.1题目内容与要求 (1)1.2题目理解与功能分析 (1)第二章概要设计 (3)2.1设计思路 (3)2.2系统模块图 (3)第三章详细设计 (4)3.1图存储结构的建立 (4)3.2求关键路径的算法 (5)第四章调试分析 (7)参考文献 (10)附录(程序清单) (11)第一章需求分析1.1 题目内容与要求内容:自拟定合适的方式从键盘上输入一个AOE网,使用图的邻接表存储结构存储该AOE网,然后求出该AOE网的关键路径。
输入AOE网的方式要尽量的简单方便,程序要能够形象方便地观察AOE网和它的关键路径基本要求:1.熟悉图的存储结构及操作方式;2.熟悉求关键路径的算法;3.熟练运用开发环境;4.完成软件的设计与编码;5. 熟练掌握基本的调试方法;6. 提交符合课程设计规范的报告;1.2 题目理解与功能分析该题实质要求用数据结构中的图形知识编写一个求无循环有向帯权图中从起点到终点所有路径,经分析、比较求出长度最大路径,从而求出关键路径。
通常我们用有向图表示一个工程。
在这种有向图中,用顶点表示活动,用有向边<Vi,Vj>表示活动Vi必须先于活动Vj进行。
如果在这种图中用有向边表示一个工程中的各项活动(ACTIVITY),用有向边上的权值表示活动的持续时间(DURATION),用顶点表示事件(EVENT),则这种的有向图叫做用边表示活动的网络,简称AOE网络。
在AOE网络中,从源点到各个顶点,可能不止一条。
这些路径的长度也可能不同。
不同路径所需的时间虽然不同,但只有各条路径上所有活动都完成了,这个工程才算完成。
因此,完成整个工程所需的时间取决于从源点到汇点的最长路径长度,即在这条路径上所有活动的持续时间之和。
这条路径长度就叫做关键路径(critical path)。
程序所要达到的功能:输入并建立AOE网;输出关键活动并求出这个工程的关键路径;求出完成这个关键路径的最少时间并输出,该程序结束。
第二章概要设计2.1 设计思路基本设计思路:(1) 以某一个求无循环有向帯权图蓝本。
(2) 观察并记录这个图中每个弧的起始点及权值。
(3) 用记录的结果建立AOE网,即边表示活动的网络,并用图的形式表示。
(4) 用领接表来存储图这些信息。
(5) 用Create( )函数建立AOE图。
(6) 用CriticPath ( )函数求出最大路径,并打印出关键路径。
(7) 编写代码并测试。
2.2 系统模块图图2-1系统模块图第三章详细设计3.1 图存储结构的建立1. 先建立邻接表的存储单元,为建立邻接表做准备。
为图中每个顶点建立一个单链表,第i个单链表中的结点表示依附于顶点vi的边(对于有向图是以vi 为尾的弧)。
每个结点由3个域组成,其中邻接域(adjvex)指示与顶点vi邻接的点在图中的位置,链域(nextedge)指示下一条边或弧的结点,权值域(W)存储边或弧的权值大小。
在表头结点除了设有链域(firstedge)指向链表中第一个结点之外,还设有存储顶点v或其他有关的数据域(data)和存储顶点入度的域(id)(代码如下)。
typedef struct node {int adjvex;int w;struct node *nextedge;}edgenode;typedef struct {char data;int id;edgenode *firstedge;}vexnode;2. 然后构造有向图。
第一,输入顶点信息存储在顶点表中,并初始化该顶点的便表。
第二,首先输入边所依附的两个顶点的序号i和j然后生成新的邻接点序号为j的边表结点,最后将该结点插入到第i个表头部。
(代码如下)for(int k=0;k<arcnumber;k++) {scanf("%d,%d,%d",&begin,&end,&duttem);p=(edgenode*)malloc(sizeof(edgenode));p->adjvex =end-1;p->w =duttem;Graph[end-1].id ++;p->nextedge =Graph[begin-1].firstedge ;Graph[begin-1].firstedge =p;3.2 求关键路径的算法利用AOE网进行工程管理时,需解决的两个主要问题:其一,计算完成整个工程的最短工期;其二,确定关键路径,以找出哪些活动时影响工程进度的关键。
计算其过程必须分别在拓扑有序和逆拓扑有序的前提下进行。
也就说,ve[k]必须在事件vk所有前驱的最早发生的时间求得之后才能确定。
因此,可以在拓扑排序的基础上计算ve[k]和vl[k]。
由此得到求解关键路径的方法:首先输入e条有向边<i,j>,建立AOE网的邻接表存储结构;然后从始点出发,令事件的最早发生时间为0,按拓扑有序求其余各顶点时间的最早发生时间ve[k];其次从终点出发,令事件最迟发生时间等于其最早发生时间,按你你逆拓扑排序求其余各顶点事件最迟发生时间 vl[k]。
最后根据各顶点事件的ve和vl值,求所有活动最早开始时间ee和最迟开始时间el。
如果某活动满足条件ee=el,则为关键活动。
if(el[i]==ee[i]) {printf(" 此弧为关键活动 ");}同时,为计算各顶点事件的ve值是在拓扑排序的过程中进行的,因此需一个队列来记录拓扑排序,如果顶点的入度为0,则该顶点从队尾进入队列,拓扑排序时,从队头出队列。
第四章调试分析在调试的过程中,遇到过很多的问题,我觉得在这之中的比较具有技术含量的问题就是在求事件的最晚发生的时间时,不知如何着手,然后我翻阅了一些书籍和上网查了一些资料,最后确定采用堆栈的方法,保存拓扑排序的顶点序列,然后根据后进先出的原则,进行求事件的最晚发生世间的计算。
另外就是很多的特殊情况需要考虑,比如说有向图含有环,这种情况是要编程加以排除,开始事件有多个,关键路径不只一条等一些很细节的问题。
第一组测试方案及结果如下:图4-1 建立有向图图4.2 邻接表输出图图4.3 关键路径输出图第二组测试方案及结果如下:图4.4 建立有向图图4.5 邻接表输出图图4.6 关键路径输出图签。
参考文献[1] 严蔚敏编.数据结构(C语言版).北京: 清华大学出版社,1997.2[2] 谭浩强著.C语言程序设计(第二版).北京: 清华大出版社,2001.3[3] 夏克俭编著.数据结构.北京: 国防工业出版社,2000.7[4] 彭勃.数据结构.北京: 电子工业出版社,2007.6[5] 宜晨编著.Visual C++5.0实用培训教程.北京:电子工业出版社,1998.5附录(程序清单)#include<iostream>#include<string>using namespace std;typedef string Vertex;typedef int InfroType;/*存放权值*/#define null 0const int MAXN = 20;typedef struct ArcNode{int adjvex;struct ArcNode * nextarc;InfroType Infro;bool flag;}ArcNode;typedef struct VNode{Vertex data;int count;ArcNode *firstarc;}VNode;typedef struct Graph{VNode adjlist[MAXN];int n, e;}Graph;int visited[MAXN];int ve[MAXN];int vl[MAXN];int stack[MAXN];int st[MAXN];int tp;int top;int max(int x, int y){if( x > y) return x;else return y;}int min(int x, int y){if(x < y)return x;else return y;}void Init(Graph * & g){int i;g->n = 0;g->e = 0;for(i = 0; i < MAXN; i++){g->adjlist[i].firstarc = null;g->adjlist [i].count = 0;}}bool Empty(Graph * g){if( g->n == 0 && g->e == 0 )return true;elsereturn false;}int Find(Graph * g,Vertex v){if(Empty(g)){cout << "图为空." << endl;return -1;}int i;for(i = 0; i < g->n; i++)if(g->adjlist[i].data == v)return i;return -1;}void Create(Graph * & g){int i, i1, i2;Vertex v1, v2;InfroType w;cout << "请输入顶点数和边数: " << endl;cin >> g->n >> g->e;cout << "请输入顶点:" << endl;for(i = 0; i < g->n; i++)cin >> g->adjlist[i].data ;ArcNode * p;p = null;cout << "边和权值: " << endl;for(i = 1; i <= g->e; i++){cin >> v1 >> v2 >> w ;i1 = Find(g, v1);i2 = Find(g, v2);if( i1 != -1 && i2 != -1){p = new ArcNode;p->adjvex = i2;p->Infro = w;p->flag = false;p->nextarc = g->adjlist[i1].firstarc ;g->adjlist [i1].firstarc = p;}}}void Output(Graph *g)/*按照存储结构输出*/{if(Empty(g)){cout << "图为空." << endl;return;}int i;cout << "按照邻接表输出为: " << endl;for( i = 0; i < g->n; i++){cout << g->adjlist [i].data;ArcNode * p;p = g->adjlist [i].firstarc ;while(p){cout << " ---> " << "(" << g->adjlist[p->adjvex ].data << "," << p->Infro << ")" ;p = p->nextarc ;}cout << endl;}}bool Topsort(Graph * g, int &infro, int & v){int stack[MAXN];int st[MAXN];int tp;int top;memset(ve, 0, sizeof(int) * MAXN);Rdu(g, 1);top = -1;tp = -1;int i, m, n;ArcNode * p;p = null;infro = 0;for(i = 0; i < g->n; i++)if(g->adjlist [i].count == 0){if(g->adjlist [i].firstarc && infro < g->adjlist [i].firstarc ->Infro ){infro = g->adjlist [i].firstarc ->Infro ;}}m = v;for(i = 0; i < g->n; i++)if(!g->adjlist [i].firstarc){if( v == m)v = i;else{cout << "结束事件不唯一." << endl;return false;}}if(infro == -1){cout << "没有找到开始事件. " << endl;return false;}if(v == -1){cout << "没有找到结束事件." << endl;return false;}for(i = 0; i <= g->n; i++)vl[i] = INT_MAX;for(i = 0; i < g->n; i++)if(g->adjlist [i].count == 0)stack[++top] = i;while( top + 1 ){m = stack[top--];g->adjlist [m].count = -1;st[++tp] = m;p = g->adjlist [m].firstarc ;while(p){n = p->adjvex ;if(g->adjlist [n].count == -1){cout << "该有向图有环." << endl;return false ;}ve[n] = max(ve[n],ve[m] + p->Infro) ;g->adjlist [n].count --;if(g->adjlist [n].count == 0)stack[++top] = n;p = p->nextarc;}}if(tp < g->n - 1){cout << "拓扑排序不成功." << endl;return false;}elsecout << "拓扑排序成功." << endl;vl[tp] = ve[tp];tp--;while(tp + 1){p = g->adjlist [st[tp]].firstarc ;while(p){vl[st[tp]] = min(vl[st[tp]], vl[p->adjvex ] - p->Infro );p = p->nextarc ;}p = g->adjlist [st[tp]].firstarc ;while(p){if(vl[st[tp]] == vl[p->adjvex ] - p->Infro )p->flag = true;p = p->nextarc ;}tp--;}return true;}void Path(Graph * g,int u, int v,int path[], int d) {int j, i;ArcNode * p;p = null;visited[u] = 1;d++;path[d] = u;p = g->adjlist [u].firstarc ;if(u == v){cout << "关键路径: ";cout << g->adjlist [path[0]].data;for(i = 1; i <= d; i++)cout << "--->" << g->adjlist [path[i]].data;cout << " 总工期: " << ve[v] << endl;}while(p){j = p->adjvex ;if(visited[j] == 0 && vl[j] == ve[j] && p->flag )Path(g, j, v, path, d);p = p->nextarc ;}visited[u] = 0;d--;}void CriticPath(Graph * g){if(Empty(g)){cout << "图为空." << endl;return;}int infro, v, i;infro = -1;v = -1;if(Topsort(g, infro, v) == false || infro == -1 || v == -1){return ;}Rdu(g, 1);for(i = 0; i < g->n; i++)if(g->adjlist [i].count == 0 && g->adjlist [i].firstarc && g->adjlist [i].firstarc ->Infro == infro){memset(visited, 0, sizeof(int) * MAXN);memset(st, 0, sizeof(int) * MAXN);Path(g, i, v, st, -1);}}void Menu(){cout << " 有向网的相关操作" << endl;cout << " 新建有向网-------------------->1" << endl;cout << " 输出邻接表-------------------->2" << endl; cout << " 输出关键路径------------------>3" << endl;cout << " 退出-------------------------->0" << endl;cout << "请输入..." << endl;}void main(){Graph * g;g = new Graph;Init(g);int choose;while(1){Menu();cin >> choose;switch(choose){case 1: Init(g); Create(g); break;case 2: O utput(g); break;case 3: CriticPath(g); break;default: return;}}}沈阳航空航天大学课程设计报告。