图-关键路径

版权声明:转载请注明出处。 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);
		   }
	   }
}

...

猜你喜欢

转载自blog.csdn.net/baidu_38304645/article/details/83038718