拓扑排序
概念
AOV网:顶点表示活动,弧表示活动先后关系的 有向图
结点表示事件,是时刻;
所以一个节点包含了:
前一个活动的结束事件和下一个活动的开始事件
而弧表示过程,代表活动的持续时间
有某个集合上的一个偏序(<=关系)的到该集合上一个全序,该操作称为拓扑排序
拓扑排序-方法
(计算各顶点的入度, 将度为零的顶点入栈)
1 从图中没有前驱的顶点中选择一个并输出
(出栈,更新后继结点的入度,若入度为0,入栈)
2 从图中 删除此顶点 及所有从其出发的弧
3 重复上述两步,至图空 或图不空但不存在无前驱的顶点(好像有环的存在)
(根据输出的点数,判断是否存在闭环)
实现
Status TopologicalSort(ALGraph G)
{
//indegree是个数组
FindInDegree(G, indegree);
InitStack(S);
for (int i = 0; i <G.vexnum; i++)
if (indegree[i] == 0) Push(S, i);
cnt = 0;
while (StackEmpty(S) == FALSE)
{
Pop(S, i);
OutputElem(G.vertices[i].data);
cnt++;
for (p = G.vertices[i].firstarc; p != NULL; p = p->nextarc)
{
k = p->adjvex;
indegree[k]--;
if (indegree[k] == 0)
Push(S, k);
}
}
if (cnt < G.vexnum)
return ERROR;
else
return OK;
}
关键活动
关键活动:必须在具备执行条件的第一时间启动活动,否则会导致延期
即保证工期前提下最早开始时间和最晚开始时间相同的活动
顶点状态最早/晚激活时间: ee(act) = ve(头) el(act) = vl(尾) - dur(act)
求顶点状态的最早激活时间
ve(源点) = 0
对于普通顶点v, 设W为其前驱顶点集W
//为什么要用max函数?
//因为 活动v 必须在前面所有准备活动都做好了之后可以激活
ve(v) = max(ve(w) + dut(w, v) | w ∈ W)
按照什么顺序来逐个计算各个顶点的最早激活时间?
感觉是按照拓扑序
按照拓扑序逐个计算,找各顶点的前驱不方便怎么办?
如求ve(e)可在处理b和c时及时更新保留最大
Status GetVEAndTvsTopOrd(AlGraph G, Stack &T)
{
for (int i = 0; i < G.vexnum; i++)
ve[i] = 0;
FindInDegree(G, indegree);
InitStack(S);
//为了方便后面求个顶点最晚激活时间还要用栈T记录拓扑逆序
InitStack(T);
for (int i = 0; i < G.vexnum; i++)
if (indegree[i] == 0)
Push(S, i);
cnt = 0;
while (!StackEmpty(S))
{
Pop(S, j);
Push(T, j);
cnt++;
for (p = G.vertices[j].firstarc; p != NULL; p = p->nextarc)
{
k = p->adjvex;
indegree[k]--;
if (indegree[k] == 0) Push(S, k);
if (ve[j] + *(p->info) > ve[k])
ve[k] = ve[j] + *(p->info);
}
}
if (cnt < G.vexnum)
return ERROR;
else
return OK;
}
关键路径-方法-求顶点状态的最晚到达时间
vl(终点) = ve(终点)
对普通顶点v, 设W为其后继顶点的集合,则
//为了保证所有v后面的活动都能在ve(终点)之前完成
//所以要求出vl的最小值
vl(v) = min{vl(w) - dut(v,w) | w ∈ w}
按照什么顺序来逐个计算各个顶点的最完激活时间
拓扑逆序(T的出栈顺序,逐个元素根据其后继的ve值和弧权跟新)
初始化各顶点vl值为工期,按照拓扑逆序逐个节点更新其自身的vl值
根据当前元素的后继ve值和弧权更新
Status CriticalPath(ALGraph G)
{
InitStack(T);
if (!GetVEAndTvsTopOrd(G, T))
return ERROR;
for (int i = 0; i < G.vexnum; i++)
vl[i] = ve[i];
while (StackEmpty(T) == FALSE)
{
Pop(T, j);
for (p = G.vertices[j].firstarc; p != NULL; p = p->nextarc)
{
k = p->adjvex;
dur = *(p->info);
if (vl[k] - dut < vl[j])
vl[j] = vl[k] - dut;
}
}
for (j = 0; j < G.vexnum; j++)
{
for (p = G.vertices[j].firstarc; p != NULL; p = p->nextarc)
{
k = p->adjvex;
dut = *(p->info);
ee = ve[j];
el = vl[k] - dut;
if (ee == el)
printf("critical actv\n");
else
printf("no critical actv\n");
}
}
}