leetcode 787. Cheapest Flights Within K Stops

13 篇文章 0 订阅
3 篇文章 0 订阅

leetcode 787. Cheapest Flights Within K Stops

题目描述

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.

Note:

  • The number of nodes n will be in range [1, 100], with nodes labeled from 0 to n - 1.
  • The size of flights will be in range [0, n * (n - 1) / 2].
  • The format of each flight will be (src, dst, price).
  • The price of each flight will be in the range [1, 10000].
  • k is in the range of [0, n - 1].
  • There will not be any duplicated flights or self cycles.

Difficulty: medium
787. Cheapest Flights Within K Stops


中文描述
给你有n个城市,m个航班,每个航班是一个三元组包含出发地u,终点v,价格w的三个信息,要求你在转乘不超过k次的情况下,从起始点src到终点dst的最便宜的方法。


输入格式
第一个输入n表示城市个数,第二个输入列表edges表示每个航班的起始点,目的地,价格的信息,第三个输入src为出发点,第四个输入dst为终点,第五个输入k表示需要最多换乘k次。


Examples:

  1. Input: n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]], src = 0, dst = 2, k = 1
    Output: 200
    解释:
    从0到2有两种方法,可以从0 –> 1 –> 2,价格为200,或则0–>2,价格500.
    因为可以转乘一次,所以最少为200

  2. Input: n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]], src = 0, dst = 2, k = 0
    Output: 500
    解释:
    从0到2有两种方法,可以从0 –> 1 –> 2,价格为200,或则0–>2,价格500.
    因为不能转乘,所以最少为500


解答思路

  • 解法一:dfs + memory

    原问题为在转机不超过k次的情况下,从srcdst的价格最少。记mid为从src起飞能到的城市之一。原问题转化为最小化在不超过k-1次的情况下,从middst的价格+srcmid的价格。即 minmid{Psrc>mid,1+Pmid>dst,k1} 。可以用dfs,遍历所有情况,用memory记录下经历过的转态,避免重复计算。

  • 解法二:应用heapq

    思路和上述差不多,不过每次我们都从当前费用最小的往外扩展,如果遇到满足题目要求的方法后就可以直接跳出,可以减少一些不必要的计算。

  • 解法三:动态规划

    用一个二维的dp数组,dp[i][j]表示在不超过i次转机的情况下,从j到达dst的最少费用。dp[i][j]= mink {dp[i-1][k]+ Pk>j }
    (从自己到自己为0, Pk>k=0线Pk>j=inf


代码

解法一

class Solution(object):
    def findCheapestPrice(self, n, flights, src, dst, K):
        """
        :type n: int
        :type flights: List[List[int]]
        :type src: int
        :type dst: int
        :type K: int
        :rtype: int
        315ms dfs + memory
        """
        # 把原始数据处理下,按起始点划分
        import collections
        flights_dict = collections.defaultdict(list)
        for flight in flights:
            flights_dict[flight[0]].append(flight[1:])
        # 用来记录已经计算过的位置
        memory = {}
        def dfs(K, src, price):
            # 如果该位置已经被访问过,直接输出结果
            if (src, K) in memory:
                return memory[(src, K)]
            # 不能到达的情况,记录下来
            if K < 0:
                memory[(src, K)] = float('inf')
                return float('inf')

            min_price = float('inf')
            # 遍历所有从该点出发的方案
            for next_src in flights_dict[src]:
                price += next_src[1]
                if next_src[0] == dst:
                    a = price
                else:
                    a = dfs(K - 1, next_src[0], 0) + price
                # 选择价格最少的
                min_price = min(a, min_price)
                price -= next_src[1]
            # 记录下来
            memory[(src, K)] = min_price
            return memory[(src, K)]
        ans = dfs(K, src, 0)
        return ans if ans != float('inf') else -1

解法二,参考了其它人写的代码详细请见Easy and Concise Solution Using Priority Queue [Java/Python]

class Solution(object):
    def findCheapestPrice(self, n, flights, src, dst, K):
        """
        :type n: int
        :type flights: List[List[int]]
        :type src: int
        :type dst: int
        :type K: int
        :rtype: int
        88ms heapq
        """
        import heapq, collections
        flights_dict = collections.defaultdict(list)
        for flight in flights:
            flights_dict[flight[0]].append(flight[1:])
        h = [(0, src, 0)]
        while h:
            a = heapq.heappop(h)
            if a[1] == dst:
                return a[0]
            for next_src in flights_dict[a[1]]:
                if a[2] < K + 1:
                    heapq.heappush(h, (next_src[1] + a[0], next_src[0], a[2] + 1))
        return -1

解法三:

class Solution(object):
    def findCheapestPrice(self, n, flights, src, dst, K):
        """
        :type n: int
        :type flights: List[List[int]]
        :type src: int
        :type dst: int
        :type K: int
        :rtype: int
        176ms dp
        """
        import collections
        # 记录同一个终点的不同起点和价格
        flights_dict_end = collections.defaultdict(list)
        for flight in flights:
            flights_dict_end[flight[1]].append([flight[0], flight[2]])
        # 用来记录各种情况,n个站点,还剩K次,到达目的地最少价格
        dp = [[float('inf') for i in range(n)] for i in range(K + 1)]
        # 初始化能直达的
        for i in flights_dict_end[dst]:
            dp[0][i[0]] = i[1]
        # 反向推回去
        for k in range(1, K + 1):
            for pos in range(n):
                for before in flights_dict_end[pos]:
                    dp[k][before[0]] = min(dp[k][before[0]], dp[k-1][pos] + before[1])
                dp[k][pos] = min(dp[k][pos], dp[k-1][pos])
        ans = dp[K][src]
        return ans if ans != float('inf') else -1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值