关键路径需要拓扑排序算法。对AOV网进行拓扑排序的基本思路是:从AOV网中选择一个入度为0的顶点,然后删除此顶点为尾的弧,继续重复此步骤,直到输出全部顶点或者AOV网中不存在入度为0的顶点为止。
拓扑排序主要是为解决一个工程问题能否顺利进行的问题,但有时我们还需要解决工程需要的最短时间问题。在AOV网的基础上,我们引入一个新概念AOE网:在一个表示工程的带权有向图中用顶点表示事件,用有向边代表活动,用边上的权值代表活动持续时间。它具有明显的工程特性。如在某个顶点代表的事件发生后,从该顶点出发的活动才能开始。只有在进入某顶点的活动都已经结束,该顶点代表的事件才能发生。
尽管AOE网和AOV网都是用来对工程建模的,但他们还有很大的不同,主要是体现在AOV网顶点表示活动的网,它只描述活动之间的制约关系,而AOE网是用边表示活动的网,边上的权值表示活动持续的时间。因此,AOE网是建立在活动之间制约关系没有矛盾的基础上,再来分析完成整个工程至少需要多少时间,或者缩短完成工程所需要的时间,应该加快那些活动等问题。
- 事件最早发生的时间 ve[k]: 是指从开始到顶点Vk的最大路径长度。这个长度决定了所有从顶点Vk发出的活动能够开工的最早时间
ve[1]=0
ve[k] = max{ve[j] + len<vj,vk>} (<vj,vk> ∈ p[k] ) p[k] 表示所有到达vk的有向边集合 通过循环来替换max。
2.事件最迟发生时间 vl[k] :是指在不推迟整个工期的前提下,事件vk允许的最晚发生时间。
vl[n]=ve[n]
vl[k] = min{vl[j] - len<vk,vj>} (<vk,vj> ∈ s[k] ) s[k] 表示所有从vk发出的有向边集合
代码讲解:
// 最短路径
public boolean[] criticalPath() {
// 还有一个值来节省简单的计算
int tempValue;
// 第一步 tempInDegrees数组只要是有边,值为1.
int[] tempInDegrees = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
for (int j = 0; j < numNodes; j++) {
if (weightMatrix.getValue(i, j)!=-1) {
tempInDegrees[j]++;
} // Of if
} // Of for j
} // Of for i
System.out.println("In-degree of nodes: "+Arrays.toString(tempInDegrees));
// 第二步,拓扑排序
int[] tempEarliestTimeArray = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
// 这个结点不能被移除
if (tempInDegrees[i]>0) {
continue;
} // Of if
System.out.println("Removing: " + i);
for (int j = 0; j < numNodes; j++) {
if (weightMatrix.getValue(i, j)!=-1) {
tempValue = tempEarliestTimeArray[i] + weightMatrix.getValue(i, j);
if (tempEarliestTimeArray[j]<tempValue) {
tempEarliestTimeArray[j] = tempValue;
} // Of if
tempInDegrees[j]--;
} // Of if
} // Of for j
} // Of for i
System.out.println("Earlest start time: " + Arrays.toString(tempEarliestTimeArray));
// 第三步 每个点的出度
int[] tempOutDegrees = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
for (int j = 0; j < numNodes; j++) {
if (weightMatrix.getValue(i, j)!=-1) {
tempOutDegrees[i]++;
} // Of if
} // Of for j
} // Of for i
System.out.println("Out-degree of nodes;"+Arrays.toString(tempOutDegrees));
// 第四步 逆序拓扑排序
int[] tempLatesTimeArray = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
tempLatesTimeArray[i] = tempEarliestTimeArray[numNodes-1];
} // Of for i
for (int i = numNodes-1; i>=0; i--) {
// 不能被移除的结点
if (tempOutDegrees[i]>0) {
continue;
} // Of if
System.out.println("Removing "+i);
for (int j = 0; j < numNodes; j++) {
if (weightMatrix.getValue(i, j)!=-1) {
tempValue = tempLatesTimeArray[i] - weightMatrix.getValue(j, i);
if (tempLatesTimeArray[j]>tempValue) {
tempLatesTimeArray[j] = tempValue;
} // Of if
tempOutDegrees[j]--;
System.out.println("The out-degree of " + j + " decreases by 1.");
} // Of if
} // Of for j
} // Of for i
System.out.println("Latest start time: "+Arrays.toString(tempLatesTimeArray));
boolean[] resultCriticalArray = new boolean[numNodes];
for (int i = 0; i < numNodes; i++) {
if (tempEarliestTimeArray[i]==tempLatesTimeArray[i]) {
resultCriticalArray[i] = true;
} // Of if
} // Of for i
System.out.println();
return resultCriticalArray;
} // Of criticalPath
// 程序入口
public static void main(String args[]) {
Net tempNet0 = new Net(3);
System.out.println(tempNet0);
int[][] tempMatrix1 = { { 0, 9, 3, 6 }, { 5, 0, 2, 4 }, { 3, 2, 0, 1 }, { 2, 8, 7, 0 } };
Net tempNet1 = new Net(tempMatrix1);
System.out.println(tempNet1);
// Dijkstra
tempNet1.dijkstra(1);
// An undirected net is required.
int[][] tempMatrix2 = { { 0, 7, MAX_DISTANCE, 5, MAX_DISTANCE }, { 7, 0, 8, 9, 7 },
{ MAX_DISTANCE, 8, 0, MAX_DISTANCE, 5 }, { 5, 9, MAX_DISTANCE, 0, 15, },
{ MAX_DISTANCE, 7, 5, 15, 0 } };
Net tempNet2 = new Net(tempMatrix2);
tempNet2.prim();
// A directed net without loop is required.
// Node cannot reach itself. It is indicated by -1.
int[][] tempMatrix3 = { { -1, 3, 2, -1, -1, -1 }, { -1, -1, -1, 2, 3, -1 },
{ -1, -1, -1, 4, -1, 3 }, { -1, -1, -1, -1, -1, 2 }, { -1, -1, -1, -1, -1, 1 },
{ -1, -1, -1, -1, -1, -1 } };
Net tempNet3 = new Net(tempMatrix3);
System.out.println("-------critical path");
tempNet3.criticalPath();
}// Of main