一、AOV网(Activity On Vertex Network)
在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,称为AOV网。
不能存在回路。
拓扑序列
设G(V,E)是一个具有n个顶点的有向图,V中的顶点序列满足若从顶点v~i~到v~j~有一条路径,则在顶点序列中v~i~必须在v~j~之前,称这样的一个顶点为拓扑序列。
二、拓扑排序算法
基本思路
从AOV网中选择一个入度为0的顶点输出,然后删去此顶点,并删除以此顶点为尾的弧,继续重复此步骤,直到输出全部顶点或者AOV网中不存在入度为0的点为止。
AOV网要一直删除顶点,所以用邻接表表示图比较合适。考虑到算法中要查找入度为0的点,所以在原顶点结点中增加一个入度域即可。
代码如下:
//拓扑排序
private static boolean TopologicalSort(){
EdgeNode edgeNode = new EdgeNode();
int i,k;
int gettop = 0;
int top = 0; //栈指针下标
int count = 0; //输出顶点的个数
Stack<Integer> stack = new Stack<>();
for(i = 0; i < adjList.verNum; i++){
if(adjList.vertexNodes[i].in == 0) {
stack.push(i);
}
}
while (! stack.empty()){
gettop = stack.pop();
System.out.print(adjList.vertexNodes[gettop].data+" -> ");
count++;
for(edgeNode = adjList.vertexNodes[gettop].firstEdge; edgeNode != null; edgeNode = edgeNode.next){
k = edgeNode.adjvex;
if(--adjList.vertexNodes[k].in == 0)
stack.push(k);
}
}
return count >= adjList.verNum;
}
三、AOE网
在一个表示工程的带权有向图中,用顶点表示事件,用有向边表示活动,用边上的权值表示活动的持续时间,这种有向图的边表示活动的网,称为AOE网(Activity On Edge Network)。
关键路径
路径上各个活动所持续的时间之和称为路径长度,从源点到汇点具有最大长度的路径叫关键路径,在关键路径上的活动叫关键活动。
- 在工程活动中,耗费的时间取决于关键路径的长度;
- 拓扑排序解决了一个工程能否顺利进行的问题,关键路径解决了工程完成所需的最短时间问题。
算法基本思想
找到所有活动的最早开始时间和最晚开始时间,比较它们,如果相等就意味着此活动是关键活动,活动间的路径是关键路径,反之则不是。
代码如下:
//求关键路径
private static void CriticalPath(){
ltv = new int[adjList.verNum];
EdgeNode edgeNode = new EdgeNode();
int i,gettop,j;
int k = 0;
int ete=0;
int lte = 0; //最早发生时间和最迟发生时间
if(TopologicalSort()) {
for (i = 0; i < adjList.verNum; i++) {
ltv[i] = etv[adjList.verNum - 1];
}
while (!stack2.empty()) {
gettop = stack2.pop();
for (edgeNode = adjList.vertexNodes[gettop].firstEdge; edgeNode != null; edgeNode = edgeNode.next) {
k = edgeNode.adjvex;
if (ltv[k] - edgeNode.weight < ltv[gettop]) {
ltv[gettop] = ltv[k] - edgeNode.weight;
}
}
}
for (j = 0; j < adjList.verNum; j++) {
for (edgeNode = adjList.vertexNodes[j].firstEdge; edgeNode != null; edgeNode = edgeNode.next) {
k = edgeNode.adjvex;
ete = etv[j];
lte = ltv[k] - edgeNode.weight;
if (ete == lte) {
System.out.printf("<v%d, v%d> length: %d \n ", j,k, edgeNode.weight);
}
}
}
}
}
//拓扑排序
private static boolean TopologicalSort(){
etv = new int[adjList.verNum];
EdgeNode edgeNode = new EdgeNode();
int i,k;
int gettop = 0;
int count = 0; //输出顶点的个数
Stack<Integer> stack = new Stack<>();
for(i = 0; i < adjList.verNum; i++){
if(adjList.vertexNodes[i].in == 0) {
stack.push(i);
}
}
for (i = 0; i < adjList.verNum; i++){
etv[i] = 0;
}
System.out.println("拓扑序列为:");
while (! stack.empty()){
gettop = stack.pop();
System.out.print(adjList.vertexNodes[gettop].data+" -> ");
count++;
stack2.push(gettop); // 拓扑序列压栈
for(edgeNode = adjList.vertexNodes[gettop].firstEdge; edgeNode != null; edgeNode = edgeNode.next){
k = edgeNode.adjvex;
if(--adjList.vertexNodes[k].in == 0)
stack.push(k);
if(etv[gettop]+edgeNode.weight > etv[k]){ //求各顶点最早发生时间
etv[k] = etv[gettop] + edgeNode.weight;
}
}
}
System.out.println();
return count >= adjList.verNum;
}
时间复杂度为O(n+e),e为边数。