题目描述
有 n
个城市通过一些航班连接。给你一个数组 flights
,其中 flights[i] = [fromi, toi, pricei]
,表示该航班都从城市 fromi
开始,以价格 pricei
抵达 toi
。
现在给定所有的城市和航班,以及出发城市 src
和目的地 dst
,你的任务是 找到出一条最多经过 k 站中转的路线,使得从 src 到 dst 的 价格最便宜 , 并返回该价格。 如果不存在这样的路线,则输出 -1。
力扣:787. K 站中转内最便宜的航班
输入:
n = 3, edges = [[0 , 1 , 100] , [1 , 2 , 100] , [0 , 2 , 500]]
src = 0 , dst = 2 , k = 1
输出: 200
题目分析: 既然是求最短路径,BFS 也是可以的,不过,考虑到用例非常大的情况,我们需要认真的思考剪枝的方案,本题我们申请一个 ans[] 数组记录从 src 到 i 的最小价格,下次再遍历到 i 时,如果价格比记录的值小才计算,否则直接丢弃。
class Solution {
private int INF = 1000007;
public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
List<int[]>[] g = new List[n];
// 将 flights 转换为邻接表
for(int i = 0 ; i < n ; i ++){
g[i] = new ArrayList<>();
}
for(int[] flight : flights){
g[flight[0]].add(new int[]{flight[1] , flight[2]});
}
// 表示 src 到 i 最小价格
int[] ans = new int[n];
Arrays.fill(ans , INF);
Queue<int[]> que = new LinkedList<>();
que.offer(new int[]{src , 0});
// 退出条件加上 k 的限制
while(!que.isEmpty() && k >= 0){
int size = que.size();
for(int i = 0 ; i < size ; i ++){
int[] temp = que.poll();
for(int[] path : g[temp[0]]){
int distance = temp[1] + path[1];
// 剪枝1: 小于 i 之前记录的最小值 , 且小于 dst 之前记录的最小值
if(distance < ans[path[0]] && distance < ans[dst]){
ans[path[0]] = distance;
// 剪枝2: 到 dst 了就不用继续往下了
if(path[0] != dst){
que.offer(new int[]{path[0] , distance});
}
}
}
}
k --;
}
return ans[dst] >= INF ? -1 : ans[dst];
}
}