【图论】关键路径求法c++

代码结构如下图:

其中topologicalSort(float**, int, int*, bool*, int, int)用来递归求解拓扑排序,topologicalSort(float**, int*&, int, int, int)传参图的邻接矩阵mat与结点个数n,与一个引用变量数组topo,返回一个布尔值表示该图是否存在拓扑排序,同时将引用变量数组topo赋值为该图的拓扑序列。

getEdges(float**, int**&, int)传参图的邻接矩阵mat,引用变量二维数组edge,结点数n。然后将返回该图的边数,同时将float赋值为一个存储图的边的起点与终点的edgeNum * 2维的数组。

aoe(float**, int, int*&, int&, float*&, float*&, float*&, float*&, int*&, int**&, int&)分别传参邻接矩阵mat,结点数n,引用变量criticalPath表示关键路径,引用变量ve,vl,e,l正如名字所示,topo与edges表示拓扑序列与边,edgeNum表示边的数量。

aoe(float**, int, int*&, int&, float*&, float*&, float*&, float*&)与上一个函数差不多,只是少了topo与edges,edgeNum两个参数,并且多了一个布尔类型的返回值,返回的是关键路径是否存在。

aoe(float**, int*&, int&)则更是只有三个参数,他不对ve,vl,e,l进行返回。

aoe

cpp 复制代码
static const float INF = 1.0f/0.0f;

// x is what you are, and y is meaning to you are the no.y numbers to sort.
void topologicalSort(float** mat, int n, int* arr, bool* flags, int x=0, int y=0) {

	arr[y] = x;
	flags[x] = true;

	float tmp[n];

	// first, set all the elements of the no.x row to INF, and store the original value to tmp;
	// just like delete this vertex
	for (int i = 0; i < n; ++i) {
		tmp[i] = mat[x][i];
		mat[x][i] = INF;
	}

	for (int i = 0; i < n; ++i) {

		int k = (x + i) % n;

		// if k have not recorded in arr.
		if (!flags[k]) {

			bool flag = true;

			// this loop is aim to find a vertex whose in_degree is equals to 0.
			for (int j = 0; j < n; ++j) {
				if (j != k && mat[j][k] != INF) {
					flag = false;
					break;
				}
			}

			// if you delete x, the in_degree of k is equals to 0. so do a recursive call.
			if (flag) {
				topologicalSort(mat, n, arr, flags, k, y+1);
			}

		}

	}

	// restore the no.x row
	for (int i = 0; i < n; ++i) {
		mat[x][i] = tmp[i];
	}

}

bool topologicalSort(float** mat, int* &topo, int n, int x=0, int y=0) {

	topo = new int[n];
	bool *flags = new bool[n];

	for (int i = 0; i < n; ++i) {
		flags[i] = false;
	}

	topologicalSort(mat, n, topo, flags, x, y);

	for (int i = 0; i < n; ++i) {
		if (!flags[i]) return false;
	}

	return true;

}

int getEdges(float** mat, int** &edges, int n) {

	// e is for the edges, whose account is unsure
	// ans is for the number of edges
	int ans = 0;
	int** e = new int*[n * (n - 1)];

	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < n; ++j) {
			if (i == j || mat[i][j] == INF) continue;
			e[ans++] = new int[]{i, j};
		}
	}

	// copy e into edges
	edges = new int*[ans];
	for (int i = 0; i < ans; ++i) {
		edges[i] = e[i];
	}

	delete[] e;

	return ans;

}

void aoe(float** mat, int n, int* &criticalPath, int &length, float* &ve, float* &vl, float* &e, float* &l, int* &topo, int** &edges, int &edgeNum) {

	ve = new float[n];
	vl = new float[n];
	e = new float[edgeNum];
	l = new float[edgeNum];

	for (int i = 0; i < n; ++i) {
		ve[i] = 0;
	}

	for (int i = 1; i < n; ++i) {

		int max = i;

		for (int j = 0; j < i; ++j) {
			if (mat[topo[j]][topo[i]] == 0 || mat[topo[j]][topo[i]] == INF) continue;
			if (ve[topo[j]] + mat[topo[j]][topo[i]] > ve[topo[max]] + mat[topo[max]][topo[i]]) {
				max = j;
			}
		}

		ve[topo[i]] = ve[topo[max]] + mat[topo[max]][topo[i]];

	}

	for (int i = 0; i < n; ++i) {
		vl[i] = ve[topo[n - 1]];
	}

	for (int i = n - 2; i >= 0; --i) {

		int min = i;

		for (int j = i + 1; j < n; ++j) {
			if (mat[topo[i]][topo[j]] == 0 || mat[topo[i]][topo[j]] == INF) continue;
			if (vl[topo[j]] - mat[topo[i]][topo[j]] < vl[topo[min]] - mat[topo[i]][topo[min]]) {
				min = j;
			}
		}

		vl[topo[i]] = vl[topo[min]] - mat[topo[i]][topo[min]];

	}

	for (int i = 0; i < edgeNum; ++i) {
		e[i] = ve[edges[i][0]];
		l[i] = vl[edges[i][1]] - mat[edges[i][0]][edges[i][1]];
	}

	int* critical = new int[n];
	critical[0] = topo[0];
	length = 1;

	for (int i = 0; i < n; ++i) {
		critical[i] = -1;
	}

	for (int i = 0; i < edgeNum; ++i) {
		float le = l[i] - e[i];
		if (le < 1e-32) {
			critical[edges[i][0]] = edges[i][1];
			length++;
		}
	}

	criticalPath = new int[length];
	int p = 0;
	int q = 0;

	while (p != -1) {
		criticalPath[q++] = p;
		p = critical[p];
	}

	delete[] critical;

}

bool aoe(float** mat, int n,  int* &criticalPath, int &length, float* &ve, float* &vl, float* &e, float* &l) {

	int* topo;
	int flag = topologicalSort(mat, topo, n);
	if (!flag) return false;
	int** edges;
	int edgeNum = getEdges(mat, edges, n);

	aoe(mat, n, criticalPath, length, ve, vl, e, l, topo, edges, edgeNum);

	return true;

}

bool aoe(float** mat, int n,  int* &criticalPath, int &length) {

	float* ve;
	float* vl;
	float* e;
	float* l;

	return aoe(mat, n, criticalPath, length, ve, vl, e, l);

}

在main函数中进行一个测试,传参如下图:
2 3 5 3 9 6 4 2 3 v1 v2 v3 v4 v5 v6

cpp 复制代码
int main() {

	int n = 6;

	float** mat = new float*[] {
			new float[] {0,	2,		3,		INF,	INF,	INF	},
			new float[] {INF,	0,		INF,	5,		INF,	INF	},
			new float[] {INF,	3,		0,		9,		4,		INF	},
			new float[] {INF,	INF,	INF,	0,		6,		2	},
			new float[] {INF,	INF,	INF,	INF,	0,		3	},
			new float[] {INF,	INF,	INF,	INF,	INF,	0	}
	};

	char** value = new char*[n]{
		"v1", "v2", "v3", "v4", "v5", "v6"
	};

	float *ve, *vl, *e, *l;
	int* criticalPath;
	int length;

	int** edges;
	int* topo;

	topologicalSort(mat, topo, n);
	int edgeNum = getEdges(mat, edges, n);
	aoe(mat, n, criticalPath, length, ve, vl, e, l);

	cout << "拓扑排序为:";
	for (int i = 0; i < n; ++i) {
		cout << value[topo[i]] << " ";
	}
	cout << "\n\n";

	cout << "共有" << edgeNum << "条边:\n";
	for (int i = 0; i < edgeNum; ++i) {
		cout << value[edges[i][0]] << "->" << value[edges[i][1]] << ": " << mat[edges[i][0]][edges[i][1]] << endl;
	}
	cout << endl;

	for (int i = 0; i < n; ++i) {
		cout << '\t' << value[i];
	}
	cout << endl;

	cout << "ve:";
	for (int i = 0; i < n; ++i) {
		cout << '\t' << ve[i];
	}
	cout << endl;

	cout << "vl:";
	for (int i = 0; i < n; ++i) {
		cout << '\t' << vl[i];
	}
	cout << "\n\n";

	for (int i = 0; i < edgeNum; ++i) {
		cout << '\t' << value[edges[i][0]] << "->" << value[edges[i][1]];
	}
	cout << endl;

	cout << "e:";
	for (int i = 0; i < edgeNum; ++i) {
		cout << '\t' << e[i];
	}
	cout << endl;

	cout << "l:";
	for (int i = 0; i < edgeNum; ++i) {
		cout << '\t' << l[i];
	}
	cout << endl;

	cout << "l-e:";
	for (int i = 0; i < edgeNum; ++i) {
		cout << '\t' << l[i] - e[i];
	}
	cout << "\n\n";

	cout << "关键路径为:";
	for (int i = 0; i < length; ++i) {
		cout << value[criticalPath[i]] << " ";
	}

	return 0;

}

运行结果如下:

相关推荐
大卫的纯爱战士1 小时前
c++指针和引用之高难度(二)习题讲解
开发语言·c++
小oo呆1 小时前
【机器学习300问】135、决策树算法ID3的局限性在哪儿?C4.5算法做出了怎样的改进?
算法·决策树·机器学习
潜水大王2 小时前
C++轻量级 线程间异步消息架构(向曾经工作的ROSA-RB以及共事的DOPRA的老兄弟们致敬)
c++·架构
画饼校长2 小时前
【C++ Primer Plus学习记录】函数的基本知识
开发语言·c++·学习·visualstudio·软件工程
情系明明2 小时前
使用c++设计一个计算器
数据结构·c++·算法
烛九_阴3 小时前
【讨论C++继承】
开发语言·c++
少年没有乌托邦。3 小时前
C++ 类与对象(中)
c++
神州问学3 小时前
存算一体架构或成为AI处理器技术发展关键
人工智能·算法·语言模型·架构·gpu算力
“αβ”4 小时前
c语言的烫烫烫烫烫??
c语言·开发语言·c++
一个闪现必杀技5 小时前
数据结构速成--查找
数据结构