关键路径、拓扑排序的求解演示过程

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

目录
一、题目概述(内容及要求) (2)
二、功能分析 (2)
三、设计 (4)
四、运行与测试 (8)
五、总结 (11)
参考文献 (11)
一、题目概述(内容及要求)
1、什么是拓扑排序?
简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称
之为拓扑排序。

如何进行拓扑排序?解决的方法很简单:
(1)在有向图中选一个没有前驱的顶点且输入之。

(2)从图中删除该结点和所有以它为尾的弧。

重复上述两步,直至全部顶点均已输出,或者当前图中不存在无前驱的顶点
为止。

后一种情况则说明有向图中存在环。

AOE-网是一个带权的有向无环图,其中,顶点表示事件,弧表示活动,权
表示活动持续的时间。

在AOE-网络中有些活动顺序进行,有些活动并行进行。


于整个工程只有一个开始点和一个完成点,故在正常情况下(无环),网中只有
一个入度为零的点(称作源点)和一个出度为零的点(叫做汇点)。

由于AOE-网中有些活动可以并行的进行,所以完成工程的最短时间是从开
始点到完成点的最长路径长度(这里所说的路径长度是指路径上个活动持续时间
之和,不是路径上弧的数目)。

路径长度最长的路径叫做关键路径。

2、求关键路径的算法:
(1)输入e条弧<j,k>,建立AOE-网的存储结构;
(2)从源点v0出发,令ve[0]=0,按拓扑有序求其余各顶点的最早发生时间ve[i](1≤i≤n-1)。

如果得到的拓扑有序序列中顶点个数小于网
中顶点数n,则说明网中存在环,不能求关键路径,算法终止;否则
执行步骤(3)。

(3)从汇点v n出发,令vl[n-1]=ve[n-1],按拓扑有序求其余各顶点的最迟发生时间vl[i](n-2≥i≥2);
(4)根据各顶点的ve和vl值,求每条弧s的最早开始时间e(s)和最迟开始时间l(s)。

(5)若某条弧满足条件e(s)=l(s),则为关键路径。

二、功能分析
1.拓扑排序:即判定该图是否为有向无环图,构成一个AOE-网。

2.求关键路径:最短时间的求得,通过求得路径的长度——路径上各活动持续时间之和。

其中,路径最长的路径就是关键路径。

拓扑排序和求关键路径的功能图如下:
图一拓扑排序的功能图
图二拓扑排序的功能图
三、设计
图三主要流程图
图四拓扑排序算法流程图
1.程序设计的主界面代码如下:
char ch;
for(;;)
{
do
{
system("cls");
printf("===========================================\n"); printf("| 欢迎进入求关键路径算法程序|\n");
printf("%s","(S)tart开始输入工程数据并求出关键路径\n"); printf("%s","(E)xit退出!\n");
printf("===========================================\n"); printf("%s","请输入选择(S,E):");
scanf("%c",&ch);
ch=toupper(ch);
}
while(ch!='S'&&ch!='E');
switch(ch)
{case'S': seekkeyroot();break;
case'E': return 1;
}
}
2.进行输入数据的代码如下:
int projectnumer,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");
3.程序的执行部分,即进行拓扑排序找关键路径代码如下:
printf("某项目的开始到结束在图中的工程输入<vi,vj,dut>\n");
printf("如:1 3 6 回车表示第一个工程到第三个工程之间的活动用了6个小时\n");
for(int k=0;k<activenumber;k++)
{
scanf("%d %d %d",&begin,&end,&duttem);
p=(edgenode*)malloc(sizeof(edgenode));
p->adjvex=end-1; //将邻接点序号j赋给新结点的邻接点域
p->dut =duttem;
Graphicmap[end-1].id ++; //将入度加1
p->next =Graphicmap[begin-1].link;
Graphicmap[begin-1].link =p; //将新结点插入到顶点vi的边表头部
}
} //求关键路径
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));
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;
4.程序的输出部分代码如下:
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("| %3d | %3d | %7d | %7d | %3d |",Graphicmap[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;
}//寻找关键路径
四、运行与测试
首先,运行程序,无错误,程序运行的主界面如图七所示;其次,参照清华大学出版
社《数据结构(c语言版)》严蔚敏吴伟民编著书中的图,如图五所示建立AOE网输入
相关信息进行程序的测试,程序结果如图八所示,关键路径为如图六所示,图九为无法拓扑
排序求关键路径。

图五AOE网
图六关键路径
图七程序运行主界面
图八运行结果图
图九无法拓扑排序的情况
五、总结
通过对拓扑排序和求关键路径的操作,首先加强了对图的存储结构和图的遍历的进一步的熟悉和应用,在拓扑排序中还让我们去应用以前学习的栈的知识温故的同时也在实践的信得理论。

对图的应用实在生活中应用很广泛,同时图的知识点和算法也是我们这学期学习的精华,例如求关键路径,用到栈,拓扑排序等经典算法,让我们受益匪浅。

参考文献
清华大学出版社数据结构(c语言版)严蔚敏吴伟民编著
附录
源程序代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<iomanip.h>
#include <process.h>
#include <ctype.h>
typedef struct node//边表结点类型
{
int adjvex;//顶点的序号
int dut; //边上的权值
struct node *next; //指向下一条边的指针
}edgenode;
typedef struct //顶点表结点
{
int projectname; //顶点域
int id; //顶点入度
edgenode *link; //边表头指针
}vexnode;//建立图存储结构
void CreateGraphic(vexnode* Graphicmap,int projectnumber,int activenumber) //projectnumber为工程的节点数,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("如:1 3 6 回车表示第一个工程到第三个工程之间的活动用了6个小时\n");
for(int k=0;k<activenumber;k++)
{
scanf("%d %d %d",&begin,&end,&duttem);
p=(edgenode*)malloc(sizeof(edgenode));
p->adjvex=end-1; //将邻接点序号j赋给新结点的邻接点域
p->dut =duttem;
Graphicmap[end-1].id ++; //将入度加1
p->next =Graphicmap[begin-1].link;
Graphicmap[begin-1].link =p; //将新结点插入到顶点vi的边表头部}
} //求关键路径
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));
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("| %3d | %3d | %7d | %7d | %3d |",Graphicmap[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("===========================================\n"); printf("| 欢迎进入求关键路径算法程序|\n");
printf("%s","(S)tart开始输入工程数据并求出关键路径\n"); printf("%s","(E)xit退出!\n");
printf("===========================================\n"); printf("%s","请输入选择(S,E):");
scanf("%c",&ch);
ch=toupper(ch);
}
while(ch!='S'&&ch!='E');
switch(ch)
{case'S': seekkeyroot();break; case'E': return 1;
}
}
}。

相关文档
最新文档