在一个表示工程的带权有向图中,用顶点表示事件,用有向边表示活动,用边上的权值表示活动的持续时间,这种有向图的边表示活动的网,我们叫做AOE网(Activity On Edge Network)。AOE网中没有入度的顶点称为源点或始点,没有出度的顶点称为终点。AOE网是要建立在活动之间制约关系没有矛盾的基础之上,再来分析完成整个工程至少需要多少时间。
我们把路径上各个活动所持续的时间之和叫做路径长度,从源点到终点具有最大长度的路径叫做关键路径,在关键路径上的活动叫关键活动。我们找到所有活动的最早开始时间和最晚开始时间,如果它们相等,则此活动是关键活动,活动间的路径为关键路径。如果不相等,则就不是。
我们定义一下四个参数:
1.事件的最早发生时间 etv,即顶点Vk的最早发生时间;
2.事件的最晚发生时间 ltv,即顶点Vk的最晚发生时间;
3.活动的最早开工时间 ete,边Ak的最早发生时间;
4.活动的最早开工时间 lte,边Ak的最晚发生时间;
我们由1和2可以求得3和4,然后在根据 ete 和 lte 是否相等来判断活动k是否为关键活动。
求事件的最早发生时间 etv[i] 的过程,就是从头到尾找拓扑序列的过程,因此,在求关键路径之前,需要先调用一次拓扑序列算法的代码来计算 etv[i] 和拓扑序列列表。
代码如下:
//边表结点
typedef struct EdgeNode
{
int adjvex;//邻接点域,存储该顶点对应的下标
int weight;//存储权值
struct EdgeNode * next;
}EdgeNode;
//顶点表结构
typedef struct VertexNode
{
int in;//顶点入度
int data;//顶点域,存储顶点信息
EdgeNode * firstedge;//边表头指针
}VertexNode;
typedef struct GraphAdjList
{
VertexNode adjList[MAXVEX];
int vertexNum;
}GraphAdjList;
int etv[VERTEX],ltv[VERTEX];//事件最早发生时间和最晚发生时间
int stack2[VERTEX];//用于存储拓扑序列的栈
int top2;//指向stack2的栈顶
void TopologicalSort(GraphAdjList GL)
{
EdgeNode * e;
int i,k,gettop;
int top = -1;//指向栈顶
int count = 0;//统计输出顶点的个数
int stack[MAXVEX];//用栈来存储入度为0的顶点
for (i = 0; i < GL.vertexNum; i++)
if (GL.adjList[i].in == 0)
stack[++top] = i;//将入度为0的顶点入栈
top2 = -1;
for (i = 0; i < GL.vertexNum; i++)
etv[i] = 0;//初始化为0
while (top != -1)
{
gettop = stack[top--];//出栈
count++;
stack2[++top2] = gettop;//将弹出的顶点序号压入拓扑序列的栈
e = GL.adjList[gettop].firstedge;
while (e != NULL)//遍历此顶点的弧表
{
k = e->adjvex;
if (!(--GL.adjList[k].in))//入度为0则入栈
stack[++top] = k;
if ((etv[gettop] + e->weight) > etv[k])//求各顶点事件最早发生时间值
etv[k] = etv[gettop] + e->weight;
e = e->next;
}
}
if (count < GL.vertexNum)
printf("有回路");
}
void CriticalPath(GraphAdjList GL)
{
EdgeNode * e;
int i,gettop,k,j;
int ete,lte;//声明活动最早发生时间和最迟发生时间
TopologicalSort(GL); //求拓扑序列,计算数组etv和stack2的值
for (i = 0; i < GL.vertexNum; i++)
ltv[i] = etv[GL.vertexNum - 1];//初始化ltv
while (top2 != -1)//计算ltv
{
gettop = stack2[top2--];//将拓扑序列出栈,后进先出
e = GL.adjList[gettop].firstedge;
while (e != NULL)
{//求各顶点事件的最迟发生时间ltv
k = e->adjvex;
if (ltv[k] - e->weight < ltv[gettop])
ltv[gettop] = ltv[k] - e->weight;
e = e->next;
}
}
for (j = 0; j < GL.vertexNum; j++)
{
e = GL.adjList[j].firstedge;
while (e != NULL)
{
k = e->adjvex;
ete = etv[j]; //活动最早发生时间
lte = ltv[k] - e->weight;//活动最迟发生时间
if (ete == lte)//两者相等即在关键路径上
printf("<V%d,V%d> length: %d, ",
GL.adjList[j].data,GL.adjList[k].data,e->weight);
e = e->next;
}
}
}
可以结合下图分析: