787. K 站中转内最便宜的航班
有 n 个城市通过一些航班连接。给你一个数组 flights ,其中 flights[i] = [fromi, toi, pricei] ,表示该航班都从城市 fromi 开始,以价格 pricei 抵达 toi。
现在给定所有的城市和航班,以及出发城市 src 和目的地 dst,你的任务是找到出一条最多经过 k 站中转的路线,使得从 src 到 dst 的 价格最便宜 ,并返回该价格。 如果不存在这样的路线,则输出 -1。
示例 1:
输入:
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 1
输出: 200
解释:
城市航班图如下
从城市 0 到城市 2 在 1 站中转以内的最便宜价格是 200,如图中红色所示。
解析:
这是一道最短路径问题,可是有一个步数k的限定,dijkstra无法限定步数,spfa也不可以,那就要考虑spfa的原生算法,Bellman Ford
Bellman Ford/SPFA 都是基于动态规划,其原始的状态定义为 f[i][k],f[i][k] 代表从起点到 i 点,且经过最多 k 条边的最短路径。这样的状态定义引导我们能够使用 Bellman Ford 来解决有边数限制的最短路问题。
同样多源汇最短路算法 Floyd 也是基于动态规划,其原始的三维状态定义为 f[i][j][k],f[i][j][k] 代表从点 i 到点 j,且经过的所有点编号不会超过 k(即可使用点编号范围为 [1, k])的最短路径。这样的状态定义引导我们能够使用 Floyd 求最小环或者求“重心点”(即删除该点后,最短路值会变大
class Solution {
public:
int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k) {
//dp[i][j] 表示走了i步,到达j点花费最小
vector<vector<int>> dp(k + 2, vector<int>(n + 1, INT_MAX / 2));
dp[0][src] = 0;
for(int i = 1; i <= k + 1; i++) {
for(auto &k : flights) {
int x = k[0], y = k[1], z = k[2];
dp[i][y] = min(dp[i - 1][x] + z, dp[i][y]);
}
}
int ans = INT_MAX / 2;
for(int i = 0; i <= k + 1; i++) {
ans = min(ans, dp[i][dst]);
}
return ans == INT_MAX / 2 ? -1 :ans;
}
};