题目概述
There are n cities connected by m flights. Each fight starts from city u and arrives at v with a price w.
Now given all the cities and fights, together with starting city src
and the destination dst
, your task is to find the cheapest price from src
to dst
with up to k
stops. If there is no such route, output -1
.
Example1
Input:
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 1
Output: 200
Explanation:
The graph looks like this:
temp1.png
The cheapest price from city 0 to city 2 with at most 1 stop costs 200, as marked red in the picture.
Input:
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 0
Output: 500
Explanation:
The graph looks like this:
temp2.png
The cheapest price from city 0 to city 2 with at most 0 stop costs 500, as marked blue in the picture.
分析
此题考察图论知识,本质上为单源最短路径问题,这种问题可以优先使用Bellman-Ford方法解决:
int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int K) {
vector<int> dist(n, 1e8); // 初始距离设定为很大
dist[src] = 0;
for (int i = 0; i <= K; i++) { // 最多K次中继
vector<int> temp(dist); // 需要引入临时数组记录中间变化
for (auto edge : flights) // Bellman-Ford
dist[edge[1]] = min(dist[edge[1]] , dist[edge[0]] + edge[2]);
dist = temp;
}
return dist[dst] == 1e8 ? -1 : dist[dst];
}
当然,以上思想还可以写成动态规划方法的形式,会更加容易理解。为此,我们需要构造一个二维数组ans,其中的任意一个元素[i][j]表示从起点在j步之内到达结点i的最短路径长度。于是可以得到:
K++;
vector<vector<int>> ans(n, vector<int>(K+1));
for (int i = 0; i < n; i++)
for (int j = 0; j <= K; j++)
ans[i][j] = 1e8; // 数组初始化
ans[src][0] = 0;
for (int i = 1; i <= K; i++) {
for (int j = 0; j < n; j++) // 从j-1步的情况中拷贝当前最短路径
ans[j][i] = ans[j][i-1];
for (const vector<int>& f: flights) // Bellman-Ford
ans[f[1]][i] = min(ans[f[1]][i], ans[f[0]][i-1] + f[2]);
}
return (ans[dst][K] == 1e8) ? -1 : ans[dst][K];
总结
· 最短路径问题,常见的解决算法有两种,一为Dijsktra,一为Bellman-Ford。对于单源路径问题,采用后者更加直观,但该算法效率较低,时间复杂度达到了O(V*E)级别
· 使用Bellman-Ford进行迭代更新时需要注意,赋值时参与比较的是上一步达到的最短路径加上新路径的和,为此需要引入临时数组拷贝上一次的最短路径,否则会出现错误。