1、关键路径

  有向无环图方可求关键路径;

  AOE网络,研究的问题是:(1)、完成整项工作至少需要多少时间?(2)、哪些活动是影响工程进度的关键?

  在AOE网中,有些活动可以并行,所以完成工程的最短时间是从开始点到完成点的最长路径的长度,路径长度最长的路径叫做关键路径。

模型如下:

关键路径_第1张图片

2、算法思想  

  (1)、首先建立AOE网络;

  (2)、从源顶点出发,按拓扑有序求其余各个顶点的最早发生时间ve[i];

  (3)、从汇顶点出发,逆拓扑有序求其余各顶点的最迟发生时间vl[i];

  (4)、根据各顶点的ve和vl值,求每条弧s的最早开始和最晚开始时间,若相同则为关键路径;

3、算法实现

  均由C++实现(邻接矩阵实现的):

template
void GraphMtx::CriticalPath(const Type &vertex){
	int n = Graph::getCurVertex();
	int *ve = new int[n];
	for(int i = 0; i < n; i++){
		ve[i] = 0;
	}

	int v = getVertexIndex(vertex);
	int j;
	int weight;
	for(i = 0; i < n; i++){  //求各个顶点最长路径,最早可能开始时间;
		j = getFirstNeighbor(getValue(i));
		while(j != -1){
			weight = edge[i][j];
			if(ve[i] + weight > ve[j]){
				ve[j] = weight + ve[i];
			}
			j = getNextNeighbor(getValue(i), getValue(j));
		}
	}
	for(i = 0; i < n; i++){ //从头开始,输出最早开始时间
		cout<= 0; i--){  //逆序求最迟开始时间
		j = getFirstNeighbor(getValue(i));
		while(j != -1){
			weight = edge[i][j];
			if(vl[j] - weight < vl[i]){
				vl[i] = vl[j] - weight;
			}
			j = getNextNeighbor(getValue(i), getValue(j));
		}
	}
	for(i = 0; i < n; i++){ //从头开始,输出最迟开始时间
		cout< 
  

4、完整代码、测试代码、测试结果


 (1)、完整代码

#ifndef _GRAPH_H_
#define _GRAPH_H_

#include
#include
using namespace std;

#define VERTEX_DEFAULT_SIZE		10
#define MAX_COST				0x7FFFFFFF

template	
class Graph{
public:
	bool isEmpty()const{
		return curVertices == 0;
	}
	bool isFull()const{
		if(curVertices >= maxVertices || curEdges >= curVertices*(curVertices-1)/2)
			return true;  //图满有2种情况:(1)、当前顶点数超过了最大顶点数,存放顶点的空间已满
		return false;     //(2)、当前顶点数并没有满,但是当前顶点所能达到的边数已满
	}
	int getCurVertex()const{
		return curVertices;
	}
	int getCurEdge()const{
		return curEdges;
	}
public:
	virtual bool insertVertex(const Type &v) = 0;  //插入顶点
	virtual bool insertEdge(const Type &v1, const Type &v2, E cost) = 0; //插入边
	virtual bool removeVertex(const Type &v) = 0;  //删除顶点
	virtual bool removeEdge(const Type &v1, const Type &v2) = 0; //删除边
	virtual int getFirstNeighbor(const Type &v) = 0; //得到第一个相邻顶点
	virtual int getNextNeighbor(const Type &v, const Type &w) = 0; //得到下一个相邻顶点
public:
	virtual int getVertexIndex(const Type &v)const = 0; //得到顶点下标
	virtual void showGraph()const = 0;  //显示图
	virtual Type getValue(int index)const = 0; 
public:
	virtual void DFS(const Type &v) = 0;
	virtual void BFS(const Type &v) = 0;
protected:
	int maxVertices;  //最大顶点数
	int curVertices;  //当前顶点数
	int curEdges;  //当前边数
};

template
class GraphMtx : public Graph{ //邻接矩阵继承父类矩阵
#define maxVertices  Graph::maxVertices  //因为是模板,所以用父类的数据或方法都得加上作用域限定符
#define curVertices  Graph::curVertices
#define curEdges     Graph::curEdges
public:
	GraphMtx(int vertexSize = VERTEX_DEFAULT_SIZE){  //初始化邻接矩阵
		maxVertices = vertexSize > VERTEX_DEFAULT_SIZE ? vertexSize : VERTEX_DEFAULT_SIZE;
		vertexList = new Type[maxVertices]; //申请顶点空间
		for(int i = 0; i < maxVertices; i++){  //都初始化为0
			vertexList[i] = 0;
		}
		edge = new int*[maxVertices];  //申请边的行
		for(i = 0; i < maxVertices; i++){ //申请列空间
			edge[i] = new int[maxVertices];
		}
		for(i = 0; i < maxVertices; i++){ //赋初值为0 
			for(int j = 0; j < maxVertices; j++){
				if(i != j){
					edge[i][j] = MAX_COST; //初始化时都赋为到其它边要花的代价为无穷大。
				}else{
					edge[i][j] = 0;  //初始化时自己到自己认为花费为0
				}
			}
		}
		curVertices = curEdges = 0; //当前顶点和当前边数
	}
	GraphMtx(Type (*mt)[4], int sz){  //通过已有矩阵的初始化
		int e = 0; //统计边数
		maxVertices = sz > VERTEX_DEFAULT_SIZE ? sz : VERTEX_DEFAULT_SIZE;
		vertexList = new Type[maxVertices]; //申请顶点空间
		for(int i = 0; i < maxVertices; i++){  //都初始化为0
			vertexList[i] = 0;
		}
		edge = new int*[maxVertices];  //申请边的行
		for(i = 0; i < maxVertices; i++){ //申请列空间
			edge[i] = new Type[maxVertices];
		}
		for(i = 0; i < maxVertices; i++){ //赋初值为矩阵当中的值
			for(int j = 0; j < maxVertices; j++){
				edge[i][j] = mt[i][j];
				if(edge[i][j] != 0){
					e++; //统计列的边数
				}
			}
		}
		curVertices = sz;
		curEdges = e/2;
	}
	~GraphMtx(){}
public:
	bool insertVertex(const Type &v){
		if(curVertices >= maxVertices){
			return false;
		}
		vertexList[curVertices++] = v;
		return true;
	}
	bool insertEdge(const Type &v1, const Type &v2, E cost){
		int maxEdges = curVertices*(curVertices-1)/2;
		if(curEdges >= maxEdges){
			return false;
		}

		int v = getVertexIndex(v1);
		int w = getVertexIndex(v2);

		if(v==-1 || w==-1){
			cout<<"edge no exit"<::getCurVertex();
		bool *visit = new bool[n];

		for(int i = 0; i < n; i++){
			visit[i] = false;
		}
		DFS(v, visit);
		delete []visit;
	}
	void BFS(const Type &v){
		int n = Graph::getCurVertex();
		bool *visit = new bool[n];
		for(int i = 0; i < n; i++){
			visit[i] = false;
		}
		cout<";
		int index = getVertexIndex(v);
		visit[index] = true;

		queue q;  //队列中存放的是顶点下标;
		q.push(index);
		int w;
		while(!q.empty()){
			index = q.front();
			q.pop();
			w = getFirstNeighbor(getValue(index));
			while(w != -1){
				if(!visit[w]){
					cout<";
					visit[w] = true; 
					q.push(w);
				}
				
				w = getNextNeighbor(getValue(index), getValue(w));
				
			}
		}

		delete []visit;
	}
public:
	void MinSpanTree_Kruskal();
	void MinSpanTree_Prim(const Type &v);
	void CriticalPath(const Type &vertex);
public:
	void TopoLogicalSort();
	void ShortestPath(const Type &v, E *dist, int *path);
protected:
	void DFS(const Type &v, bool *visit){
		cout<";
		int index = getVertexIndex(v);
		visit[index] = true;
		int w = getFirstNeighbor(v);
		while(w != -1){
			if(!visit[w]){
				DFS(getValue(w), visit);
			}
			w = getNextNeighbor(v, getValue(w)); 
		}
	}
private:
	Type *vertexList;  //存放顶点的数组
	int **edge;  //存放边关系的矩阵
};
//////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct MstEdge{
	int x;  //row
	int y;  //col
	int cost;
}MstEdge;

int cmp(const void *a, const void *b){
	return (*(MstEdge*)a).cost - (*(MstEdge*)b).cost;
}

bool isSame(int *father, int i, int j){
	while(father[i] != i){
		i = father[i];
	}
	while(father[j] != j){
		j = father[j];
	}

	return i == j;
}
void markSame(int *father, int i, int j){
	while(father[i] != i){
		i = father[i];
	}
	while(father[j] != j){
		j = father[j];
	}

	father[j] = i;
}

template
void GraphMtx::MinSpanTree_Kruskal(){ 
	int n = Graph::getCurVertex();  //由于要用到父类的保护数据或方法,有模板的存在,必须加上作用域限定符;
	MstEdge *edge1 = new MstEdge[n*(n-1)/2];
	int k = 0;

	for(int i = 0; i < n; i++){
		for(int j = i+1; j < n; j++){
			if(edge[i][j] != MAX_COST){
				edge1[k].x = i;
				edge1[k].y = j;
				edge1[k].cost = edge[i][j];
				k++;
			}
		}
	}
	qsort(edge1, k, sizeof(MstEdge), cmp);

	int *father = new int[n];
	Type v1, v2;
	for(i = 0; i < n; i++){
		father[i] = i;
	}
	for(i = 0; i < n; i++){
		if(!isSame(father, edge1[i].x, edge1[i].y)){
			v1 = getValue(edge1[i].x);
			v2 = getValue(edge1[i].y);
			printf("%c-->%c : %d\n", v1, v2, edge1[i].cost);
			markSame(father, edge1[i].x, edge1[i].y);
		}
	}
}
template
void GraphMtx::MinSpanTree_Prim(const Type &v){
	int n = Graph::getCurVertex();
	int *lowCost = new int[n];
	int *mst = new int[n];

	int k = getVertexIndex(v);
	for(int i = 0; i < n; i++){
		if(i != k){
			lowCost[i] = edge[k][i];
			mst[i] = k;
		}else{
			lowCost[i] = 0;
		}
	}

	int min;
	int minIndex;
	int begin;
	int end;

	for(i = 0; i < n-1; i++){
		min = MAX_COST;
		minIndex = -1;

		for(int j = 0; j < n; j++){
			if(lowCost[j] != 0 && lowCost[j] < min){
				min = lowCost[j];
				minIndex = j;
			}
		}
		begin = mst[minIndex];
		end = minIndex;
		printf("%c-->%c : %d\n", getValue(begin), getValue(end), min);

		lowCost[minIndex] = 0;

		int cost;
		for(j = 0; j < n; j++){
			cost = edge[minIndex][j];
			if(cost < lowCost[j]){
				lowCost[j] = cost;
				mst[j] = minIndex;
			}
		}
		
	}
}
template
void GraphMtx::TopoLogicalSort(){
	int n = Graph::getCurVertex();
	int *count = new int[n];
	
	for(int i = 0; i < n; i++){
		count[i] = 0;
	}
	for(i = 0; i < n; i++){
		for(int j = 0; j < n; j++){
			if(edge[i][j] == 1){
				count[j]++;
			}
		}
	}

	int top = -1;
	for(i = 0; i < n; i++){
		if(count[i] == 0){
			count[i] = top;
			top = i;
		}
	}
	int v, w;
	for(i = 0; i < n; i++){
		if(top == -1){
			return;
		}else{
			v = top;
			top = count[top];
			printf("%c-->", getValue(v));
			w = getFirstNeighbor(getValue(v));
			while(w != -1){
				if(--count[w] == 0){
					count[w] = top;
					top = w;
				}
				w = getNextNeighbor(getValue(v), getValue(w));
			}
		}
	}

	cout<<"Over."<
void GraphMtx::ShortestPath(const Type &vertex, E *dist, int *path){
	int n = Graph::getCurVertex();
	bool *s = new bool[n];   //s是看当前的是否访问过的一个标记数组

	int v = getVertexIndex(vertex);
	for(int i = 0; i < n; i++){
		dist[i] = edge[v][i];
		s[i] = false;
		if(i != v && dist[i] < MAX_COST){
			path[i] = v;
		}else{
			path[i] = -1;  //自己到自己路径为和无穷路径都为-1
		}
	}

	int min;
	int weight;    //权值
	s[v] = true;
	for(i = 0; i < n-1; i++){  //除去自身顶点
		min = MAX_COST;
		int u = v;
		for(int j = 0; j < n; j++){
			if(!s[j] && dist[j] < min){
				min = dist[j];
				u = j;
			}
		}

		s[u] = true; //找到最小的,每次只找最短路径
		for(int k = 0; k < n; k++){
			weight = edge[u][k];
			if(!s[k] && weight < MAX_COST && dist[u]+weight < dist[k]){  //找最小权值的路径
				dist[k] = dist[u] + weight;
				path[k] = u; //记录下当前新的起始位置
			}
		}
	}
}
template
void GraphMtx::CriticalPath(const Type &vertex){
	int n = Graph::getCurVertex();
	int *ve = new int[n];
	for(int i = 0; i < n; i++){
		ve[i] = 0;
	}

	int v = getVertexIndex(vertex);
	int j;
	int weight;
	for(i = 0; i < n; i++){  //求各个顶点最长路径,最早可能开始时间;
		j = getFirstNeighbor(getValue(i));
		while(j != -1){
			weight = edge[i][j];
			if(ve[i] + weight > ve[j]){
				ve[j] = weight + ve[i];
			}
			j = getNextNeighbor(getValue(i), getValue(j));
		}
	}
	for(i = 0; i < n; i++){ //从头开始,输出最早开始时间
		cout<= 0; i--){  //逆序求最迟开始时间
		j = getFirstNeighbor(getValue(i));
		while(j != -1){
			weight = edge[i][j];
			if(vl[j] - weight < vl[i]){
				vl[i] = vl[j] - weight;
			}
			j = getNextNeighbor(getValue(i), getValue(j));
		}
	}
	for(i = 0; i < n; i++){ //从头开始,输出最迟开始时间
		cout< 
  

  (2)、测试代码

#include"Graph1.h"

int main(void){
    GraphMtx gm;
    gm.insertVertex('A'); //0
    gm.insertVertex('B'); //1
    gm.insertVertex('C'); //2
    gm.insertVertex('D'); //3
    gm.insertVertex('E'); //4
    gm.insertVertex('F');
    gm.insertVertex('G');
    gm.insertVertex('H');
    gm.insertVertex('I');
   
    gm.insertEdge('A','B',6);
    gm.insertEdge('A','C',4);
    gm.insertEdge('A','D',5);
    gm.insertEdge('B','E',1);
    gm.insertEdge('C','E',1);
    gm.insertEdge('D','F',2);
    gm.insertEdge('E','G',9);
    gm.insertEdge('E','H',7);
    gm.insertEdge('F','H',4);
    gm.insertEdge('G','I',2);
    gm.insertEdge('H','I',6);

	gm.showGraph();
    gm.CriticalPath('A');

    return 0;

}

  (3)、测试结果

测试图模型: