一、拓扑排序
1、AOV网络
顶点活动网络(Activity On Vertex Network),即一个有向图G,各顶点表示活动,各条边表示活动之间的领先关系。
AOV网络是一个有向无环图。
2、拓扑排序算法
(1)在图中选择一个入度为0 的顶点,并输出之;
(2)从图中删除该顶点极其所有出边,借助栈或队列存储产生的新的入读为0 的顶点;
(3)重复(1)和(2)直至输出所有顶点。
3、代码
public void TopoSort(Graph graph, int[] order) {
System.out.println("初始入度:");
for (int i = 0; i < nodeNum; i++)
System.out.print(inDegree[i] + " ");
System.out.println();
Queue<Node> queue = new LinkedList<>();
for (int i = 0; i < nodeNum; i++) {
if (inDegree[i] == 0) {
// 入度为零的节点入队列
queue.offer(vertex[i]);
}
}
int count = 0, nextPos;
for (int i = 0; i < nodeNum; i++) {
if (!queue.isEmpty()) {
Node node = queue.poll();
order[count++] = node.id;
// 将该节点的所有邻接点的入度减一
while (node.next != null) {
node = node.next;
nextPos = getVertexPos(node.id);
inDegree[nextPos]--;
if (inDegree[nextPos] == 0)
queue.offer(vertex[nextPos]);
}
}
}
System.out.println("拓扑排序:");
for (int i = 0; i < nodeNum; i++) {
System.out.print(order[i] + " ");
}
System.out.println();
}
执行结果
拓扑排序:
0 1 7 4 2 8 3 6 5
二、关键路径
1、AOE网络
顶点表示事件,有向边表示活动,有向边的权值表示活动的所需时间,入边代表活动已完成,出边表示活动刚开始。
2、关键路径
完成工程所需的最短时间,即从开始顶点到完成顶点的最长路径的长度,该最长路径称为关键路径。
3、关键路径算法
(1)求事件可能的最早发生时间earliest[]
- earliest(0) = 0
earliest(j) = max{earliest(i) + w(i,j)}
(2)求时间允许的最迟发生时间latest[]
- latest(n-1) = earliest(n-1)
latest(i) = min{latest(j) - w(i,j)}
(3)求活动的最早开始时间和最迟发生时间early[]和late[]
- early(k) = earlest(i)
late(k) = latest(j) -w(i,j)
当early[k] = late[k]时,对应的ak即为一个关键路径。
4、代码
/**
* 事件可能的最早发生时间
*
* @param g
* @param order
* @param earliest
*/
public void Earliest(Graph g, int[] order, int[] earliest) {
int i, k;
for (i = 0; i < nodeNum; i++) {
earliest[i] = 0;
}
for (i = 0; i < nodeNum; i++) {
k = order[i];
Node node = vertex[getVertexPos(k)].next;
while (node != null) {
if (earliest[node.id] < earliest[k] + node.weight)
earliest[node.id] = earliest[k] + node.weight;
node = node.next;
}
}
}
/**
* 事件允许的最晚发生时间
*
* @param g
* @param order
* @param earliest
* @param latest
*/
public void Latest(Graph g, int[] order, int[] earliest, int[] latest) {
int i, j, k;
for (i = 0; i < nodeNum; i++) {
latest[i] = earliest[nodeNum - 1];
}
for (i = nodeNum - 2; i > -1; i--) {
j = order[i];
Node node = vertex[getVertexPos(j)].next;
while (node != null) {
k = node.id;
if (latest[j] > latest[k] - node.weight)
latest[j] = latest[k] - node.weight;
node = node.next;
}
}
}
public void CriticalPath(Graph graph, int[] earliest, int[] latest) {
int[] early = new int[edgeNum], late = new int[edgeNum];
early[0] = earliest[0];
early[1] = earliest[0];
early[2] = earliest[0];
early[3] = earliest[1];
early[4] = earliest[2];
early[5] = earliest[3];
early[6] = earliest[4];
early[7] = earliest[4];
early[8] = earliest[5];
early[9] = earliest[6];
early[10] = earliest[7];
late[0] = latest[1] - a[0];
late[1] = latest[2] - a[1];
late[2] = latest[3] - a[2];
late[3] = latest[4] - a[3];
late[4] = latest[4] - a[4];
late[5] = latest[5] - a[5];
late[6] = latest[6] - a[6];
late[7] = latest[7] - a[7];
late[8] = latest[7] - a[8];
late[9] = latest[8] - a[9];
late[10] = latest[8] - a[10];
System.out.println("关键路径:");
for (int i = 0; i < edgeNum; i++) {
if (early[i] == late[i]) {
System.out.print("a" + i + " ");
}
}
System.out.println();
}
执行结果
earliest:
0 6 4 5 7 7 16 15 19
latest:
0 6 6 9 7 11 17 15 19
early:
0 0 0 6 4 5 7 7 7 16 15
late:
0 2 4 6 6 9 8 7 11 17 15
关键路径:
a0 a3 a7 a10