版权声明:转载请注明出处。 https://blog.csdn.net/baidu_38304645/article/details/83038718
顶点表示状态,弧表示活动,弧权表示完成活动所需时间。用以估算工程的完成时间。
问最短工期是多长,哪些活动是影响工期的关键活动。
关键路径(长度最长的路径)决定工期
关键活动:工程正常开展最早开始时间等最迟开始时间的活动。
创建图,并输出其活动及其权值、最早开始时间、最晚开始时间以及是否为关键活动 。
运行结果:
算法思想:
首先需要求顶点状态的最早到达时间。
ve(源点=0)
对普通顶点v,设W为其前驱结点集则 ve(v) = max{ve(w) + dut(w,v)}
初始化各顶点ve值为0.{找无前驱结点,距其ve值更新后继ve值,删除},如此重复,至图空或发现回路{实际是拓扑排序。}
各点ve初始化为零,计算入度,零入度者入栈,出栈根据其更新后继入度和ve值,删除,新零入度者入栈}重复至栈空,无全序报错。
如此我们可以在拓扑排序的代码上修改:
int ve[MVNUM];
各点ve初始化为0 计算入度 求各顶点最早到达时间计入全局数组ve。
Status TopologicalSort(ALGraph G,SqStack &T){
/*拓扑排序
将度为0的顶点入队 出队 更新后继结点的入度 若入读为0 则入队
根据输出结点数量判断是否合理
各点ve初始化为0 计算入度 求各顶点最早到达时间计入全局数组ve*/
int InDegree[MVNUM],i,k,count=0; //count对输出的结点进行计数
memset(InDegree,0,sizeof(InDegree));
memset(ve,0,sizeof(ve));
FindInDegree(G,InDegree);
LinkQueue Q;
InitQueue(Q);
InitStack(T);
for(i=0;i<G.vexnum;i++){
if(!InDegree[i])
EnQueue(Q,i);
}
while(!QueueEmpty(Q)){
DeQueue(Q,i);
Push(T,i);
count++;
OutPutElem(G.vertices[i].data);
for(ArcNode *p=G.vertices[i].firstarc;p!=NULL;p=p->nextarc){
k=p->adjvex;
InDegree[k]--;
if(!InDegree[k])
EnQueue(Q,k);
if(ve[i]+p->adj>ve[k])
ve[k]=ve[i]+p->adj;
}
}
if(count==G.vexnum)
return OK;
else
return ERROR;
}
如此可以计算顶点的最早到达时间。
然后求顶点的最晚到达时间:
vl(汇点)=ve(汇点) 对普通顶点v,设W为其后继顶点集合 ,则vl(v)=min{vl(w)-dut(v,w)}
初始化各顶点vl值为工期,按 拓扑逆序(T的出栈顺序)逐个结点更新其自身的vl值,根据其元素的后继ve值和弧权更新。
最后求出ee(act)=ve(头)与el(act)=vl(尾)-dul(act)。如果ee == el就是关键活动。
算法实现:
邻接表存储:
Status CriticalPath(ALGraph G,SqStack &T){
/*关键路径
初始化各顶点vl为工期 按拓扑逆序逐个结点更新自身的vl值 根据当前元素的后继
vl值和弧权更新 求ee、el并输出关键否 */
if(!TopologicalSort(G,T))
return ERROR;
int vl[MVNUM],i,j,k,ee,el;
for(i=0;i<G.vexnum;i++)
vl[i]=ve[G.vexnum-1];
while(!StackEmpty(T)){
Pop(T,i);
for(ArcNode *p=G.vertices[i].firstarc;p!=NULL;p=p->nextarc){
k=p->adjvex;
if(vl[i]>vl[k]-p->adj)
vl[i]=vl[k]-p->adj;
}
}
for(i=0;i<G.vexnum;i++){
for(ArcNode *p=G.vertices[i].firstarc;p!=NULL;p=p->nextarc){
k=p->adjvex;
ee=ve[i]; //<i,k>的最早到达时间
el=vl[k]-p->adj;//<i,k>的最晚到达时间
if(ee==el)
printf("%d %d %lf %d %d yes!\n",i,k,p->adj,ee,el);
else
printf("%d %d %lf %d %d no\n",i,k,p->adj,ee,el);
}
}
}
邻接矩阵存储:
Status CriticalPath(MGraph G,SqStack &T){
/*关键路径
初始化各顶点vl为工期 按拓扑逆序逐个结点更新自身的vl值 根据当前元素的后继
vl值和弧权更新 求ee、el并输出关键否*/
if(!TopologicalSort(G,T))
return ERROR;
int vl[MVNUM],i,j,ee,el;
for(i=0;i<G.vexnum;i++)
vl[i]=ve[G.vexnum-1];
while(!StackEmpty(T)){
Pop(T,i);
for(j=0;j<G.vexnum;j++) {
if(G.arcs[i][j].adj!=INFINITY){ //如果有弧
if(vl[i]>vl[j]-G.arcs[i][j].adj)
vl[i]=vl[j]-G.arcs[i][j].adj;
}
}
}
for(i=0;i<G.vexnum;i++)
for(j=0;j<G.vexnum;j++){
if(G.arcs[i][j].adj!=INFINITY){//如果连通
ee=ve[i];//<i,k>的最早到达时间
el=vl[j]-G.arcs[i][j].adj;//<i,k>的最晚到达时间
if(ee==el)
printf("%d %d %lf %d %d yes!\n",i,j,G.arcs[i][j].adj,ee,el);
else
printf("%d %d %lf %d %d no\n",i,j,G.arcs[i][j].adj,ee,el);
}
}
}
...