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

news/2024/7/15 20:12:07 标签: 图论, 算法, 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

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
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;

}

运行结果如下:
运行结果


http://www.niftyadmin.cn/n/5209124.html

相关文章

qgis添加postgis数据

左侧浏览器-PostGIS-右键-新建连接 展开-双击即可呈现 可以点击编辑按钮对矢量数据编辑后是直接入库的&#xff0c;因此谨慎使用。

Python 获取本地和广域网 IP

Python 获取本地IP &#xff0c;使用第三方库&#xff0c;比如 netifaces import netifaces as nidef get_ip_address():try:# 获取默认网络接口&#xff08;通常是 eth0 或 en0&#xff09;default_interface ni.gateways()[default][ni.AF_INET][1]# 获取指定网络接口的IP地…

线性空间(也叫向量空间)、线性运算

线性空间、线性运算 线性空间&#xff0c;也称向量空间。 假设是一个非空集合&#xff0c;是一个实数域。 在中定义了一个加法&#xff1a;即对中任何两个元素和&#xff0c;总有中另外一个元素与它们相对应&#xff0c;称为和的和&#xff0c;记作&#xff1a; 在定义了一个…

不是默认进入Linux|总是自动进入windows系统

问题描述 不是默认进入Linux系统无法主动出现boot引导自动进入windows系统 尝试无效 修复引导无效重装Grub无效重装系统无效 环境 Ubuntu 22.04 LST微星主板 解决方案 修改引导顺序&#xff1a; 开机狂按Del键&#xff0c;进入BIOS系统&#xff0c;左侧Settings 设置&…

【MySQL】mysql中不推荐使用uuid或者雪花id作为主键的原因以及差异化对比

文章目录 前言什么是UUID?什么是雪花ID?什么是MySql自增ID?优缺点对比UUID:优点1.全球唯一性2.无需数据库支持 缺点1.存储空间大2.索引效率低3.查询效率低 雪花ID&#xff1a;优点1.分布式环境下唯一性 缺点1.依赖于机器时钟2.存储空间较大3.查询效率低 MYSQL自增:优点1.简单…

拼接合并yuv序列转成mp4

ffmpeg需要用支持libx264的版本&#xff0c;如果需要&#xff0c;可以从这个网站下载编译支持libx264\x265的ffmpeg https://www.gyan.dev/ffmpeg/builds/packages/ffmpeg-6.1-essentials_build.7z #-*- coding:utf-8-*- import osif __name__ "__main__":# 1 输入…

使用C++从0到1实现人工智能神经网络及实战案例

引言 既然是要用C++来实现,那么我们自然而然的想到设计一个神经网络类来表示神经网络,这里我称之为Net类。由于这个类名太过普遍,很有可能跟其他人写的程序冲突,所以我的所有程序都包含在namespace liu中,由此不难想到我姓刘。在之前的博客反向传播算法资源整理中,我列举…

ORA-28003: password verification for the specified password failed,取消oracl密码复杂度

自己在测试环境想要使自己的Oracle数据库用户使用简单的密码方便测试&#xff0c;结果指定密码的密码验证失败 SQL> alter user zzw identified by zzw; alter user zzw identified by zzw * ERROR at line 1: ORA-28003: password verification for the specified password…