力扣每日一题2021.08.24K站中转内最便宜的航班


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

题目描述

有n个城市通过一些航班连接。给你一个数组filghts,其中filghts[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,如图中红色所示。


示例2

输入:n = 3, edges = [[0, 1, 100], [1, 2, 100], [0, 2, 500]], src = 0, dst = 2, k = 0
输出:500
解释:城市航班图见示例1,从城市0到城市2在0站中转以内的最便宜价格是500,如图中蓝色所示。


提示

  • 1 <= n <= 100
  • 0 <= filghts.length <= (n*(n-1)/2)
  • filghts[i].length == 3
  • 0 <= fromi, toi < n
  • fromi != toi
  • 1 <= pricei <= 104
  • 航班没有重复,且不存在自环
  • 0 <= src, dst, k < n
  • src != dst

思路:Dijkstra、Bellman Ford、DFS

Dijkstra

求解最低价格(可视为最短距离),很自然就会想到Dijkstra算法。但是由于有中转站数量的限制,所以需要调整Dijkstra算法以适应中转站的条件。
Dijkstra

class Solution:
    def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int:
        # Dijkstra
        import heapq
        if len(flights) == 0:
            return -1
        # 建图
        graph = defaultdict(list)
        for fromi, toi, pricei in flights:
            graph[fromi].append([toi, pricei])
        # 构建访问集合,避免重复访问城市
        visited = set()
        # 构建城市队列
        q = [src]
        while q:
            cur = q.pop()
            visited.add(cur)
            for toi, pricei in graph[cur]:
                if toi not in visited:
                    q.append(toi)
        # 遍历结束后,如果目的地不在访问集合中,说明遍历失败
        if dst not in visited:
            return -1
        # 构建二维列表,表示到达的城市、所花费的价格以及中转次数
        pq = [[0, -1, src]]
        while pq:
            price, passed, cur = heapq.heappop(pq)
            if cur == dst:
                return price
            for toi, pricei in graph[cur]:
                if passed + 1 <= k:
                    heapq.heappush(pq, [price+pricei, passed+1, toi])
        return -1

Bellman Ford

这个题是Bellman-Ford算法的模板题。该算法,每一次迭代所有的边,则第i次迭代得到的是最多走i步时,从src到各个节点的最短路径。该算法基于动态规划。
Bellman-Ford

class Solution:
    def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int:
        # Bellman Ford
        max_price = float('inf')
        price = [[max_price] * n for i in range(k+2)]
        price[0][src] = 0
        for i in range(1, k+2):
            price[i][src] = 0
            for fromi, toi, pricei in flights:
                price[i][toi] = min(price[i][toi], price[i-1][fromi] + pricei)
        return -1 if price[k+1][dst] >= max_price else price[k+1][dst]
    

DFS+记忆化

直接递归会超时,所以要用记忆化递归。
DFS+记忆化

class Solution:
    def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int:
        # DFS+记忆化
        graph = defaultdict(dict)
        for fromi, toi, pricei in flights:
            graph[fromi][toi] = pricei
        @lru_cache(None)
        def dfs(city, remain):
            if city == dst:
                return 0
            if not remain:
                return inf
            remain -= 1
            ans = inf
            for nxt in graph[city]:
                ans = min(ans, dfs(nxt, remain) + graph[city][nxt])
            return ans
        res = dfs(src, k+1)
        return res if res != inf else -1
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值