关键路径的实现

来源:互联网 发布:pyqt5 知乎问答 编辑:程序博客网 时间:2024/03/29 09:05

在介绍关键路径之前,先介绍一个拓扑排序。其实这个概念我并不是很理解,通俗的讲就是由一个节点出发,会一直走到后面的节点,不会返回到已经访问过的节点,如何判断一个图是否是拓扑排序。(1)在有向图中选一个没有前驱的顶点输出,(2)从图中删除该顶点和所有以它为尾的弧。直至图中没有节点或没有入度为0的点。
在此基础上,引入关键路径,在拓扑排序的基础上加上边的权值,完成一个工程从开始点到完成点的最长路径的长度。路径长度最长的路径叫做关键路径,关键路径上的所有活动都是关键活动。关键活动就是要找e(i)==l(i),时间最早发生时间ve,时间最晚发生时间vl。这个概念我也很难解释,挺难说清楚的,自己多看看例子吧。如何求解ve和vl呢。ve(0)=0开始向前递推ve(j) = max{ve(i)+dut(i,j)};求出ve后,vl(n-1) = ve(n-1);向后递推,vl(i) = Min{vl(j) - dut(i,j)};
#include "graph.h"
#include <stdio.h>
#include <queue>
#include <stack>
using namespace std;
//#define DEBUG


stack<int> s;                               //保存拓扑逆序 
int ve[MAX_VERTEX_NUM];                     //记录最早时间
int vl[MAX_VERTEX_NUM];                     //记录最晚时间 
/*********************************************/
/*          拓扑排序                         */
/*          参数:G                          */
/*          功能 检查图中是否有环          */
/*********************************************/
void TopologicalSort(const MGraph *g)
{
int indegree[MAX_VERTEX_NUM];          //入度                
int i,j;

for(i=0;i<g->vexnum;i++)
{
indegree[i] = 0;
ve[i] = 0;
}
//初始化节点的入度 
for(i=0;i<g->vexnum;i++)
for(j=0;j<g->vexnum;j++)
{
if(g->arcs[i][j]!=INT_MAX)
{
indegree[j]++;
}
}

int count=0;       //输出节点的个数 
queue<int> q;      //存放入度为0的点 
for(i=0;i<g->vexnum;i++)
{
if(!indegree[i]) 
{
      q.push(i);
      indegree[i]--;        //表明已入过队列 
            }
}
//依次输出入度为0的点
        //没输出一个点将相连点的入度减1
        //再将入度为0的点入队列 
while(!q.empty())
{
int temp;
temp = q.front();
s.push(temp);            //依次逆序进栈 
// printf("%d",g->vexs[i]);
count++; 
for(i=0;i<g->vexnum;i++)
{
if(g->arcs[temp][i]!=INT_MAX)
                      { 
                            indegree[i]--;              //删除节点,相邻节点入度减1 
if((ve[temp]+g->arcs[temp][i])>ve[i])
{
ve[i] = ve[temp]+g->arcs[temp][i];  //修改最早时间 
}

}
q.pop();
for(i=0;i<g->vexnum;i++)
{
if(!indegree[i]) 

q.push(i);
indegree[i]--;
                    }
}
}
if(count != g->vexnum)
printf("There is a ring!\n");
else 
    {
//        printf("拓扑排序完成!\n");
        #ifdef DEBUG
            for(i=0;i<g->vexnum;i++)
                printf("%d ",ve[i]);
            printf("\n");
        #endif
    }
}
//在求最迟发生时间时,我直接拷贝求最早发生时间的做法
//由出度开始升入 
void CriticalPath(const MGraph *g)
{
// int outdegree[MAX_VERTEX_NUM];          //出度
int i,j;

for(i=0;i<g->vexnum;i++)
{
// outdegree[i] = 0;
vl[i] = INT_MAX;             //在这赋最大值,求的是最小值 
}


/* for(i=0;i<g->vexnum;i++)
for(j=0;j<g->vexnum;j++)
{
if(g->arcs[i][j].adj!=INT_MAX)
{
outdegree[i]++;
}
}
*/
    int count;       //输出节点的个数
    count = s.top(); 
    vl[count] = ve[count];
    count = 0;
// queue<int> q;      //存放入度为0的点 
/* for(i=0;i<g->vexnum;i++)
{
if(!outdegree[i]) 
            {
q.push(i);
vl[i] = ve[i];          //汇点赋值 
            }
}

*/ //依次输出入度为0的点
        //没输出一个点将相连点的入度减1
        //再将入度为0的点入队列 
while(!s.empty())
{
int temp;
temp = s.top();
// printf("%d",g->vexs[i]);
count++; 
for(i=0;i<g->vexnum;i++)
{
if(g->arcs[i][temp]!=INT_MAX)      //以将删节点为尾的弧 
if((vl[temp] - g->arcs[i][temp]) < vl[i])
{
vl[i] = vl[temp]-g->arcs[i][temp];
}
}
s.pop();
/* for(i=0;i<g->vexnum;i++)
{
if(!indegree[i]) 
q.push(i);
}
*/ }
//求得最迟时间后,可以与最早时间比较。得关键路径。。 
if(count != g->vexnum)
printf("There is a ring!\n");
else
     {
        printf("关键路径:");
        #ifdef DEBUG
            for(i=0;i<g->vexnum;i++)
                printf("%d ",vl[i]);
        #endif
    }
for(i=0;i<g->vexnum;i++)
  if(vl[i] == ve[i])
      printf("%d ",g->vexs[i]);
}
/*test
9 11
1 2 3 4 5 6 7 8 9END
1 2 6
1 3 4
1 4 5
2 5 1
3 5 1
4 6 2
5 7 9
5 8 7
6 8 4
7 9 2
8 9 4
end*/

原创粉丝点击