[Leetcode] Cheapest Flights Within K Stops 计算最便宜票价

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.

Example 1:
Input: n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]] src = 0, dst = 2, k = 1
Output: 200 Explanation: The graph looks like this:
https://s3-lc-upload.s3.amazo...
The cheapest price from city 0 to city 2 with at most 1 stop costs 200, as marked red in the picture.

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.

给定一个数组,其中每个元素代表着从[出发城市,目的城市,飞机票价],现在再给定任意一对不一定有直飞航线的出发城市和目的城市,和最大允许的中转次数K,求具有最便宜总价的航线组合。

深度优先搜索

思路

想知道从A到B最便宜的机票组合,只要将所有从A到B在K个中转之内的所有路径组合都遍历一遍,就能找到最低的价格。然而本题的输入是城市之间的航线,所以我们还要先根据这些航线构建一个航线图。由于题中说明了不会产生环路,也不会有重复的航线,所以在遍历图时不需要检测环路。

这里需要剪枝减少搜索分叉才能通过OJ,剪枝的要点包括:

  1. 通过visited集合,记录当前路径中已经访问过的城市,本条路径中将不再访问
  2. 如果当前路径的距离已经大于之前发现的最短距离,则不用再继续向下搜索
  3. 中转次数一旦超过也不需要再向下搜索
class GraphNode:
    def __init__(self, name):
        self.name = name
        self.dsts = []
    
    def addFlight(self, dst, price):
        self.dsts.append((dst, price))
        

class Solution:
    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
        """
        flightsMap = self.constructGraph(flights)
        self.globalMin = float('inf')
        self.findFlight(flightsMap, flightsMap.get(src), 0, dst, 0, K, set())
        return -1 if self.globalMin == float('inf') else self.globalMin
        
    def findFlight(self, flightsMap, node, totalPrice, finalDst, stops, stopLimit, visited):
        if node is None or stops > stopLimit:
            return
        if self.globalMin < totalPrice:
            return
        for dst in node.dsts:
            dstName, dstPrice = dst
            nextTotalPrice = dstPrice + totalPrice
            if dstName == finalDst: # 如果找到目的地,则计算当前的距离并和最小值比较
                self.globalMin = min(self.globalMin, nextTotalPrice)
            elif flightsMap.get(dstName) is not None and self.globalMin > nextTotalPrice and dstName not in visited: # 如果不是目的地,则继续向下找,这里中转次数要加一,并且本条路径中已经访问过的节点不用再访问
                visited.add(dstName)
                self.findFlight(flightsMap, flightsMap.get(dstName), nextTotalPrice, finalDst, stops + 1, stopLimit, visited)
                visited.remove(dstName)

    def constructGraph(self, flights):
        flightsMap = {}
        for flight in flights: # 将航线按照出发城市一一加入图中
            src = flight[0]
            dst = flight[1]
            price = flight[2]
            node = flightsMap.get(src, GraphNode(src))
            node.addFlight(dst, price)
            flightsMap[src] = node
        return flightsMap
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值