刷题使我快乐,满脸开心.jpg

  • 来源:力扣(LeetCode)
  • 链接:https://leetcode.cn/problems/cheapest-flights-within-k-stops/
  • 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目

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

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

示例 2:

输入: 
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 0
输出: 500
解释: 
城市航班图如下
从城市 0 到城市 2 在 0 站中转以内的最便宜价格是 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

思路

动态规划可行,但是难在状态转移方程。有转机次数,有点对点花费,所以肯定是需要二维数组的,出发城市是给定的,常规一维数组,我们可以根据航班表得到一个从出发城市起飞到各个城市的一个花费数组,那么这里再加上转机次数,那我们就可以得到一个转机次数*从出发城市起飞到各个城市的花费的二维数组了。

当然,需要一个极大值来初始化,不过这里要注意,不能无脑用math.MaxInt。因为花费还是需要根据航班表相加计算的,这时就会造成溢出,所以可以根据提示里的值得到一个极大值 10000 * 99, 再加上个1就肯定是不可能存在的花费数值了

详情可以参考官方题解:官方题解

代码

func findCheapestPrice(n int, flights [][]int, src int, dst int, k int) int {
    // 是个可计算的值,稍微多大点可以,但是不能直接取极大值,加cost时有可能溢出,结果就不对了
    // inf := math.MaxInt
    inf := 10000 * 101 + 1
    f := make([][]int, k+2)
    for i := range f {
        f[i] = make([]int, n)
        for j := range f[i] {
            f[i][j] = inf
        }
    }
    // f[i][j] 表示 从src出发,经过i次转机,到达j的最小花费
    f[0][src] = 0
    for times := 1; times <= k+1; times++ {
        for _, flight := range flights {
            front, to, cost := flight[0], flight[1], flight[2]
            f[times][to] = min(f[times][to], f[times-1][front]+cost)
        }
    }
    ans := inf
    for t := 1; t <= k+1; t++ {
        ans = min(ans, f[t][dst])
    }
    if ans == inf {
        ans = -1
    }
    return ans
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}