实现求关键路径的算法Word格式文档下载.docx
《实现求关键路径的算法Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《实现求关键路径的算法Word格式文档下载.docx(17页珍藏版)》请在冰豆网上搜索。
图2-1系统模块图
第三章详细设计
3.1图存储结构的建立
1.先建立邻接表的存储单元,为建立邻接表做准备。
为图中每个顶点建立一个单链表,第i个单链表中的结点表示依附于顶点vi的边(对于有向图是以vi为尾的弧)。
每个结点由3个域组成,其中邻接域(adjvex)指示与顶点vi邻接的点在图中的位置,链域(nextedge)指示下一条边或弧的结点,权值域(W)存储边或弧的权值大小。
在表头结点除了设有链域(firstedge)指向链表中第一个结点之外,还设有存储顶点v或其他有关的数据域(data)和存储顶点入度的域(id)(代码如下)。
typedefstructnode{
intadjvex;
intw;
structnode*nextedge;
}edgenode;
typedefstruct{
chardata;
intid;
edgenode*firstedge;
}vexnode;
2.然后构造有向图。
第一,输入顶点信息存储在顶点表中,并初始化该顶点的便表。
第二,首先输入边所依附的两个顶点的序号i和j然后生成新的邻接点序号为j的边表结点,最后将该结点插入到第i个表头部。
(代码如下)
for(intk=0;
k<
arcnumber;
k++){
scanf("
%d,%d,%d"
&
begin,&
end,&
duttem);
p=(edgenode*)malloc(sizeof(edgenode));
p->
adjvex=end-1;
w=duttem;
Graph[end-1].id++;
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]宜晨编著.VisualC++5.0实用培训教程.北京:
电子工业出版社,1998.5
附录(程序清单)
#include<
iostream>
string>
usingnamespacestd;
typedefstringVertex;
typedefintInfroType;
/*存放权值*/
#definenull0
constintMAXN=20;
typedefstructArcNode
{
structArcNode*nextarc;
InfroTypeInfro;
boolflag;
}ArcNode;
typedefstructVNode
Vertexdata;
intcount;
ArcNode*firstarc;
}VNode;
typedefstructGraph
VNodeadjlist[MAXN];
intn,e;
}Graph;
intvisited[MAXN];
intve[MAXN];
intvl[MAXN];
intstack[MAXN];
intst[MAXN];
inttp;
inttop;
intmax(intx,inty)
if(x>
y)returnx;
elsereturny;
}
intmin(intx,inty)
if(x<
y)
returnx;
voidInit(Graph*&
g)
inti;
g->
n=0;
e=0;
for(i=0;
i<
MAXN;
i++)
{
g->
adjlist[i].firstarc=null;
adjlist[i].count=0;
boolEmpty(Graph*g)
if(g->
n==0&
&
e==0)
returntrue;
else
returnfalse;
intFind(Graph*g,Vertexv)
if(Empty(g))
cout<
<
"
图为空."
<
endl;
return-1;
n;
if(g->
adjlist[i].data==v)
returni;
return-1;
voidCreate(Graph*&
inti,i1,i2;
Vertexv1,v2;
InfroTypew;
cout<
请输入顶点数和边数:
cin>
>
n>
e;
请输入顶点:
"
cin>
adjlist[i].data;
ArcNode*p;
p=null;
边和权值:
for(i=1;
=g->
v1>
v2>
w;
i1=Find(g,v1);
i2=Find(g,v2);
if(i1!
=-1&
i2!
=-1)
{
p=newArcNode;
p->
adjvex=i2;
Infro=w;
flag=false;
nextarc=g->
adjlist[i1].firstarc;
g->
adjlist[i1].firstarc=p;
}
voidOutput(Graph*g)/*按照存储结构输出*/
return;
按照邻接表输出为:
for(i=0;
adjlist[i].data;
ArcNode*p;
p=g->
adjlist[i].firstarc;
while(p)
cout<
--->
("
adjlist[p->
adjvex].data<
"
Infro<
)"
;
p=p->
nextarc;
boolTopsort(Graph*g,int&
infro,int&
v)
intstack[MAXN];
intst[MAXN];
inttp;
inttop;
memset(ve,0,sizeof(int)*MAXN);
Rdu(g,1);
top=-1;
tp=-1;
inti,m,n;
infro=0;
adjlist[i].count==0)
if(g->
adjlist[i].firstarc&
infro<
adjlist[i].firstarc->
Infro)
{
infro=g->
Infro;
}
m=v;
if(!
g->
adjlist[i].firstarc)
if(v==m)
v=i;
else
cout<
结束事件不唯一."
returnfalse;
}
if(infro==-1)
没有找到开始事件."
if(v==-1)
没有找到结束事件."
vl[i]=INT_MAX;
stack[++top]=i;
while(top+1)
m=stack[top--];
adjlist[m].count=-1;
st[++tp]=m;
adjlist[m].firstarc;
n=p->
adjvex;
adjlist[n].count==-1)
该有向图有环."
returnfalse;
ve[n]=max(ve[n],ve[m]+p->
Infro);
adjlist[n].count--;
adjlist[n].count==0)
stack[++top]=n;
nextarc;
if(tp<
n-1)
拓扑排序不成功."
拓扑排序成功."
vl[tp]=ve[tp];
tp--;
while(tp+1)
adjlist[st[tp]].firstarc;
vl[st[tp]]=min(vl[st[tp]],vl[p->
adjvex]-p->
Infro);
if(vl[st[tp]]==vl[p->
p->
flag=true;
tp--;
returntrue;
voidPath(Graph*g,intu,intv,intpath[],intd)
intj,i;
visited[u]=1;
d++;
path[d]=u;
p=g->
adjlist[u].firstarc;
if(u==v)
关键路径:
;
adjlist[path[0]].data;
for(i=1;
=d;
--->
adjlist[path[i]].data;
总工期:
ve[v]<
while(p)
j=p->
if(visited[j]==0&
vl[j]==ve[j]&
flag)
Path(g,j,v,path,d);
p=p->
visited[u]=0;
d--;
voidCriticPath(Graph*g)
intinfro,v,i;
infro=-1;
v=-1;
if(Topsort(g,infro,v)==false||infro==-1||v==-1)
return;
adjlist[i].count==0&
Infro==infro)
memset(visited,0,sizeof(int)*MAXN);
memset(st,0,sizeof(int)*MAXN);
Path(g,i,v,st,-1);
voidMenu()
有向网的相关操作"
新建有向网-------------------->
1"
输出邻接表-------------------->
2"
输出关键路径------------------>
3"
退出-------------------------->
0"
请输入..."
voidmain()
Graph*g;
g=newGraph;
Init(g);
intchoose;
while
(1)
{
Menu();
choose;
switch(choose)
case1:
Create(g);
break;
case2:
Output(g);
case3:
CriticPath(g);
default:
return;
}
课程设计总结:
从这次给我的课程设计任务中我深刻地体会到了。
任何事情并不是想我们想的那样简单和容易。
只有扎扎时时的学习知识才能解决实际生活中的实际问题。
从这次课设中也让我明白以后要多了解相关知识,更多的做一些实践动手活动,将知识运用到实际问题中。
同时,增加自己的动手能力,这样才能便于我们更好的解决问题。
为今后打下好的基础。
在这个过程中遇到过很多的问题,有时候需要反复的修改和测试程序,在编程的过程中,随时会发现新的问题,随时要更改和调试程序。
我觉得在调试的过程中,最开始的时候出现有多条关键路径的图但是程序却只输出一条关键路径,我仔细查看程序,发现每个事件的最早开始时间和最迟开始时间是没有问题的,最终确定在采用有向图的深度优先遍历的时候,没有将访问标志数组恢复,所以只能输出一条关键路径。
当我编完程序后,我感到很欣喜,这毕竟是我的第一次课程设计任务。
能完成让我感到什么叫做编程的快乐,什么叫做乐趣。
督促我更加努力的学习我的专业课:
计算机科学与技术。
指导教师评语:
指导教师(签字):
年月日
课程设计成绩