Problem C. Increasing Shortest Path【贪心 & 最短路->DP】

在这里插入图片描述
在这里插入图片描述


题意

  • 给一个图, n n 个点 m m 条边, q q 次询问,求从 i i j j 的走过条数不超过 c c 的最短路的长度,走路的时候过的边的长度必须是不减的

  • 数据范围: 150 150 点, 3000 3000 边, 1000 1000 次询问,时间要求 30 30


题解

  • 定义 d p [ i ] [ j ] [ k ] dp[i][j][k] 为从 i i j j ,恰好走 k k 次路的最短距离。
  • 由于我们要满足路径边权递增,所以会想到给所有边按照边权排个序。然后我们依次将边加入图中,这样就可以保证路径边权是递增的。
  • 我们会注意到,由于任意两个点间的路径不能存在环(路径边权递增),所以任意两个点之间的距离至多为 n 1 n-1 ,这样我们就把 c c 减小为 n 1 n-1 了!

AC-Code

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

const int maxm = 3e3 + 5;
const int maxn = 150 + 3;
const int mod = 1e9 + 7;

struct Edge {
	int x, y, w;
	bool operator < (const Edge &t) const {
		return w < t.w;
	}
}edge[maxm];

int dp[maxn][maxn][maxn];

void update(int& a, int b) {
	if (a == -1 || b < a)	a = b; // 如果无法到达,或者b更优,更新
}

int main() {
	int T;	cin >> T;
	while (T--) {
		int N, M, Q;	cin >> N >> M >> Q;
		memset(dp, -1, sizeof dp);
		for (int i = 0; i <= N; ++i)	dp[i][i][0] = 0;
		for (int i = 1; i <= M; ++i) 
			cin >> edge[i].x >> edge[i].y >> edge[i].w;
		sort(edge + 1, edge + 1 + M);
		for (int i = 1; i <= M; ++i)  // 升序枚举所有边
			for (int start = 1; start <= N; ++start)  // 枚举起点
				for (int step = 1; step < N; ++step)  // 枚举步数
					if (dp[start][edge[i].x][step - 1] != -1)  // 如果可以从start到达这条边的起点
						update(dp[start][edge[i].y][step], dp[start][edge[i].x][step - 1] + edge[i].w); // 尝试走这条边到达edge[i].y
		for (int i = 0; i < Q; ++i) {
			int x, y, c;	cin >> x >> y >> c;
			if (c >= N)	c = N - 1; // 
			int ans = -1;
			for (int j = 0; j <= c; ++j) 
				if (dp[x][y][j] != -1)	update(ans, dp[x][y][j]);
			cout << ans << endl;
		}
	}
	return 0;
}
发布了157 篇原创文章 · 获赞 99 · 访问量 9837

猜你喜欢

转载自blog.csdn.net/Q_1849805767/article/details/104147093