[M最短路] lc787. K 站中转内最便宜的航班(Bellman-Ford算法模板+边数限制最短路+dp思想)
Posted Ypuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[M最短路] lc787. K 站中转内最便宜的航班(Bellman-Ford算法模板+边数限制最短路+dp思想)相关的知识,希望对你有一定的参考价值。
1. 题目来源
2. 题目解析
很明显的一道 Bellman-Ford
算法的模板题,边数限制最短路。其中 Bellman-Ford
是 spfa
的前身,两者属于同一个思想,且同 Floyd
都是用的 dp
的思想。而 dijkstra
算法采用的是贪心的思想。
dp
思想:
- 状态定义:
f[k][i]
表示从起点src
最多经过k
条边的所有路径中,到达i
点的最短距离。 - 状态转移:
f[k][i] = min(f[k-1][i], f[k-1][j] + w[j][i])
。即需要枚举i
的所有入边,枚举每个点进行状态转移,等价于要枚举每个点的所有入边,即枚举所有边。 - 空间优化:很明显,
f[k]
仅与f[k-1]
有关,故可以使用滚动数组,记录上一次的状态,并在状态转移的时候实用上一次的状态进行更新即可。即可将空间变为 1 维。
- 时间复杂度: O ( n k ) O(nk) O(nk)。
- 空间复杂度: O ( n ) O(n) O(n)
代码:
const int N = 105;
int dist[N], backup[N];
class Solution {
public:
int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k) {
memset(dist, 0x3f, sizeof dist);
dist[src] = 0;
for (int i = 0; i < k + 1; i ++ ) { // 枚举 k+1 条边的限制
memcpy(backup, dist, sizeof dist); // 滚动数组,backup-->f[k-1],dist-->f[k]
for (int j = 0; j < flights.size(); j ++ ) { // 枚举所有边
int a = flights[j][0], b = flights[j][1], c = flights[j][2];
dist[b] = min(dist[b], backup[a] + c);
}
}
if (dist[dst] == 0x3f3f3f3f) return -1;
return dist[dst];
}
};
简洁代码:
class Solution {
public:
const int INF = 1e8;
int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int K) {
vector<int> dist(n, INF);
dist[src] = 0;
K ++ ;
while (K -- ) {
auto cur = dist;
for (auto& e: flights) {
int a = e[0], b = e[1], c = e[2];
cur[b] = min(cur[b], dist[a] + c);
}
dist = cur;
}
if (dist[dst] == INF) return -1;
return dist[dst];
}
};
以上是关于[M最短路] lc787. K 站中转内最便宜的航班(Bellman-Ford算法模板+边数限制最短路+dp思想)的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 789. 逃脱阻碍者(贪心) / 1646. 获取生成数组中的最大值 / 787. K 站中转内最便宜的航班(有限制的最短路,重新审视迪杰斯特拉,动态规划)