友情支持

如果您觉得这个笔记对您有所帮助,看在D瓜哥码这么多字的辛苦上,请友情支持一下,D瓜哥感激不尽,😜

支付宝

微信

有些打赏的朋友希望可以加个好友,欢迎关注D 瓜哥的微信公众号,这样就可以通过公众号的回复直接给我发信息。

wx jikerizhi

公众号的微信号是: jikerizhi因为众所周知的原因,有时图片加载不出来。 如果图片加载不出来可以直接通过搜索微信号来查找我的公众号。

787. K 站中转内最便宜的航班

n 个城市通过一些航班连接。给你一个数组 flights,其中 flights[i] = [fromi, toi, pricei],表示该航班都从城市 `fromi 开始,以价格 `pricei 抵达 `toi

现在给定所有的城市和航班,以及出发城市 src 和目的地 dst,你的任务是找到出一条最多经过 k 站中转的路线,使得从 srcdst价格最便宜 ,并返回该价格。 如果不存在这样的路线,则输出 -1

示例 1:

0787 01
输入:
n = 4, flights = [[0,1,100],[1,2,100],[2,0,100],[1,3,600],[2,3,200]], src = 0, dst = 3, k = 1
输出: 700
解释: 城市航班图如上
从城市 0 到城市 3 经过最多 1 站的最佳路径用红色标记,费用为 100 + 600 = 700。
请注意,通过城市 [0, 1, 2, 3] 的路径更便宜,但无效,因为它经过了 2 站。

示例 2:

0787 02
输入:
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]], src = 0, dst = 2, k = 1
输出: 200
解释:
城市航班图如上
从城市 0 到城市 2 经过最多 1 站的最佳路径标记为红色,费用为 100 + 100 = 200。

示例 3:

0787 03
输入:n = 3, flights = [[0,1,100],[1,2,100],[0,2,500]], src = 0, dst = 2, k = 0
输出:500
解释:
城市航班图如上
从城市 0 到城市 2 不经过站点的最佳路径标记为红色,费用为 500。

提示:

  • 1 <= n <= 100

  • 0 <= flights.length <= (n * (n - 1) / 2)

  • flights[i].length == 3

  • 0 <= fromi, toi < n

  • fromi != toi

  • 1 <= pricei <= 104

  • 航班没有重复,且不存在自环

  • 0 <= src, dst, k < n

  • src != dst

思路分析

  • 一刷(深度优先搜索,超时)

  • 一刷(带备忘录的深度优先搜索)

  • 一刷(动态规划)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
 * 通过 48 / 56 个测试用例。然后超时
 *
 * @author D瓜哥 · https://www.diguage.com
 * @since 2025-05-06 18:53:25
 */
int result = Integer.MAX_VALUE;

public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
  Map<Integer, List<int[]>> srcMap = new HashMap<>();
  for (int[] flight : flights) {
    int start = flight[0];
    srcMap.computeIfAbsent(start, x -> new ArrayList<>()).add(flight);
  }
  dfs(n, srcMap, src, dst, k + 1, 0);
  return result == Integer.MAX_VALUE ? -1 : result;
}

private void dfs(int n, Map<Integer, List<int[]>> srcMap,
                 int src, int dst, int k, int expend) {
  if (k < 0) {
    return;
  }
  if (src == dst) {
    result = Math.min(result, expend);
    return;
  }
  for (int[] flight : srcMap.getOrDefault(src, Collections.emptyList())) {
    int idst = flight[1];
    int cost = flight[2];
    // 不加该判断,通过 28 / 56 个测试用例;加上,通过 48 / 56 个测试用例
    if (cost + expend >= result) {
      continue;
    }
    dfs(n, srcMap, idst, dst, k - 1, cost + expend);
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
 * @author D瓜哥 · https://www.diguage.com
 * @since 2025-05-06 21:30:38
 */
final int MAX = 100 * 10000 + 1;

public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
  Map<Integer, List<int[]>> srcMap = new HashMap<>();
  for (int[] flight : flights) {
    int start = flight[0];
    srcMap.computeIfAbsent(start, x -> new ArrayList<>()).add(flight);
  }
  int[][] memo = new int[n][k + 1];
  int result = dfs(n, srcMap, src, dst, k + 1, memo);
  return result == MAX ? -1 : result;
}

private int dfs(int n, Map<Integer, List<int[]>> srcMap,
                int src, int dst, int k, int[][] memo) {
  if (k < 0) {
    return MAX;
  }
  if (src == dst) {
    return 0;
  }
  if (memo[src][k] != 0) {
    return memo[src][k];
  }
  int result = MAX;
  for (int[] flight : srcMap.getOrDefault(src, Collections.emptyList())) {
    int idst = flight[1];
    int cost = flight[2];
    result = Math.min(result, dfs(n, srcMap, idst, dst, k - 1, memo) + cost);
  }
  memo[src][k] = result;
  return result;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
 * @author D瓜哥 · https://www.diguage.com
 * @since 2025-05-06 21:40:38
 */
public int findCheapestPrice(int n, int[][] flights, int src, int dst, int k) {
  final int MAX = 100 * 10000 + 1;
  int[][] dp = new int[k + 2][n];
  for (int i = 0; i < k + 2; i++) {
    Arrays.fill(dp[i], MAX);
  }
  dp[0][src] = 0;
  for (int i = 1; i < k + 2; i++) {
    for (int[] flight : flights) {
      int start = flight[0];
      int end = flight[1];
      int cost = flight[2];
      dp[i][end] = Math.min(dp[i][end], dp[i - 1][start] + cost);
    }
  }
  int result = MAX;
  for (int i = 1; i < k + 2; i++) {
    result = Math.min(result, dp[i][dst]);
  }
  return result == MAX ? -1 : result;
}