关键路径C++代码实现

写在开头:

先请二倍速看王卓老师讲的视频,学习思路,一看就懂。不是因为我懒得码字 相信大家和我一样:自学搜教程时 优质视频>优质博客。毕竟看着枯燥死板的文字图片容易烦躁hh。那优质视频我找到了,uu们上链接啦:😊https://www.bilibili.com/video/BV1nJ411V7bd?p=136&vd_source=e1fb32b66b09e46bb745c68d9ccad399

进入正题:

        如标题所说,我主要讲解代码实现,毕竟王老师思路讲得清晰可是就没有代码哇(不给我们抄的机会就好气😅)然后呢,理论要与实践相结合才好,所以我会通过一道咱学校oj的水题来实战。因为做题总是有技巧的,比如给的数据量较小,用邻接矩阵存储图相当方便。如果你是追求完美的人,可以写邻接表代码又臭又长,我的建议是不如熟练掌握《链式前向星》。

题目描述:

下图是一个有向无环图,节点内的数字表示该节点的序号,节点之间的连接线表示节点之间的连接方式,连接线上方的黑色数字表示该连接线的权重。本题要求:求出有向无环图中的每一个关键路径及其发生时间(示例图中每一个边的最早/最迟发生时间以边旁边的黄色/红色数字标出)

输入格式:

 第一行为2个正整数m和n,分别表示有向无环图的节点个数和边的数量。接下来n行,代表n条边。分别是起点、终点、权重,以空格分隔。(m<50,n<100)

输出格式:

按行输出有向无环图中的所有关键路径及其发生时间,按照输入样例中边的输入次序输出
如输入样例中,边的输入次序为:
0-->1
0-->2
1-->3
2-->3
2-->4
3-->4
则输出样例中,按行上述次序依次输出其中的关键路径及其发生时间:
0-->2:0
2-->3:3
3-->4:7
注意:输入数据中边的顺序不一定符合“行优先”规则。

样例输入:

5 6
0 1 3
0 2 3
1 3 2
2 3 4
2 4 4
3 4 4

样例输出:

0-->2:0
2-->3:3
3-->4:7

ac代码:

#include <bits/stdc++.h>
using namespace std;
#define MAXSIZE 101

int n, m;//n个节点,m条边
int graph[MAXSIZE][MAXSIZE];//邻接矩阵存储图
int indegree[MAXSIZE];//入度矩阵,用于拓扑排序
int ve[MAXSIZE], vl[MAXSIZE], e[MAXSIZE], l[MAXSIZE]; //分别对应视频四个数组
int tmp[MAXSIZE][2];//存储边的输入顺序信息(会发现邻接表也不能储存边的输入顺序)
int main() {
	cin >> n >> m;
	//用memset初始化只能为-1和0,原理自行百度,这里初始化-1是防止出现权重为0的情况
	memset(graph, -1, sizeof(graph));
	for (int i = 0; i < m; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		graph[u][v] = w;
		indegree[v]++;
		tmp[i][0] = u;
		tmp[i][1] = v;
	}
	queue<int>q;//拓扑用的
	stack<int>s;//逆拓扑用的
	for (int i = 0; i < n; i++)
		if (indegree[i] == 0)
			q.push(i);
	while (!q.empty()) {
		int t = q.front();
		s.push(t);//将拓扑排序再存一遍,用的时候就是逆序了
		q.pop();
		for (int i = 0; i < n; i++)
			if (graph[t][i] != -1) {
				indegree[i]--;
				if (indegree[i] == 0)
					q.push(i);
				//以上都是拓扑排序的板子
				ve[i] = max(ve[i], ve[t] + graph[t][i]);
			}
	}
	//根据最长的时间初始化节点最晚开始时间vl
	for (int i = 0; i < n; i++)
		vl[i] = ve[s.top()];
	//逆拓扑
	while (!s.empty()) {
		int t = s.top();
		s.pop();
		for (int i = 0; i < n; i++)
			if (graph[i][t] != -1)
				vl[i] = min(vl[i], vl[t] - graph[i][t]);
	}
	//判断路径最早开始时间与最晚开始时间,得出关键路径
	for (int i = 0; i < m; i++) {
		e[i] = ve[tmp[i][0]];
		l[i] = vl[tmp[i][1]] - graph[tmp[i][0]][tmp[i][1]];
		if (e[i] == l[i])
			cout << tmp[i][0] << "-->" << tmp[i][1] << ":" << e[i] << endl;
	}
	return 0;
}

然后这两个语句:ve[i] = max(ve[i], ve[t] + graph[t][i]);

                             vl[i] = min(vl[i], vl[t] - graph[i][t]);

看不懂的请结合我上篇文章加以理解,其实也就是王老师讲的思路的体现,也可反复观看视频哦。同时,自己画图加debug也助于理解。

说了这么多是不是把视频里的思路也忘了呢?😋别急,这里还有张图帮助你捋清思路:

 

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值