Codeup 问题 A: 关键路径

本文详细介绍了如何解决图论中的关键路径问题。通过拓扑排序和动态规划相结合的方法,找到网络中从源点到汇点的最长路径。在解题过程中,强调了确定源点的重要性,并提供了完整的C++代码实现。文章还分享了一种特殊的输入处理技巧,以提高代码的可读性。
摘要由CSDN通过智能技术生成

原题地址

http://codeup.hustoj.com/problem.php?cid=100000624&pid=0

解题思路

本来套了一下模板,然后一直是答案错误。
参考本篇博文:
https://blog.csdn.net/qq_33375598/article/details/104439436
发现似乎是要加一步,即确定源点是哪一个。
方法即为遍历ve数组,ve[i]=0i即为源点。
所以不能再判断e是否等于l之后直接输出关键路径,而应另外开一个数组存储路径~
参考代码有借鉴上面那篇博文的部分qwq

参考代码

#include <bits/stdc++.h>
using namespace std;
#define pb push_back
const int maxn = 30;
struct node{
	int v, w;
};

int x;  //x顶点个数 
int inDegree[maxn], ve[maxn], vl[maxn];
vector<node> G[maxn];

//求解关键路径 
stack<int> topOrder;
vector<int> ans[maxn];  //关键路径 

bool tpSortPath() {
	queue<int> q;
	int num = 0;
	
	for (int i = 0; i < x; i++) {
		if (!inDegree[i]) q.push(i);
	}
	while (!q.empty()) {
		int v = q.front();
		q.pop();
		num++;
		topOrder.push(v);
		for (int i = 0; i < G[v].size(); i++) {
			int w = G[v][i].w;
			int v1 = G[v][i].v;
			if (--inDegree[v1] == 0) q.push(v1);			
			
			if (ve[v] + w > ve[v1]) {
				ve[v1] = ve[v] + w;
			}
		}
	}
	if (num == x) return true;
	else return false;
}

int criticalPath() {
	fill(ve, ve + maxn, 0);
	if (!tpSortPath()) return -1;
	
	/*不确定汇点时,找最长的*/
	int maxLength = 0;
	for (int i = 0; i < x; i++) {
		if (ve[i] > maxLength)
			maxLength = ve[i];
	}
	
	fill(vl, vl + maxn, maxLength);
	
	int u, v, w;
	while (!topOrder.empty()) {
		u = topOrder.top();
		topOrder.pop();
		for (int i = 0; i < G[u].size(); i++) {
			v = G[u][i].v;
			w = G[u][i].w;
			if (vl[v] - w < vl[u]) {
				vl[u] = vl[v] - w;
			}
		}
	}
	vector<int> ans[maxn];
	for (int u = 0; u < x; u++) {
		for (int i = 0; i < G[u].size(); i++) {
			v = G[u][i].v;
			w = G[u][i].w;
			
			int e = ve[u];
			int l = vl[v] - w;			
			//if (e == l) printf("(%c,%c) ", u + 'a', v + 'a');
			if (e == l) 
				ans[u].pb(v); 
		}
	}
	/*要找源点!!*/
	int s;  //源点
	for (int i = 0; i < x; i++) {
		if (ve[i] == 0) {
			s = i;  //找到源点 
			break;
		}
	} 
	
	while (ans[s].size()) {  //没有后继结点时退出 
		printf("(%c,%c) ", s + 'a', ans[s][0] + 'a');
		s = ans[s][0];
	}
	
	return maxLength;
}

int main() {
	int n, y, w;
	char a, b;
	string nu;
	cin >> n;
	while (n--) {
		//初始化
		scanf("%d%d", &x, &y);
		char str[maxn];
		scanf("%s", str);
		for (int i = 0; i < maxn; i++) G[i].clear();
		fill(inDegree, inDegree + maxn, 0);
		//getchar();
		//getline(cin, nu);
		//cout << nu << endl;
		while (y--) {
			scanf("%*c%c %c %d", &a, &b, &w);  //这里也是参考写的输入方式
			                                  //%*c意思是读入一个字符但是忽略它 
			//cout << a << b << w << endl;
			int v1 = a - 'a';  //求得结点的值 
			int v2 = b - 'a';
			G[v1].pb(node{v2, w});
			inDegree[v2]++;
		}
		int ans = criticalPath();
		printf("%d\n", ans);
	}
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值