leetcode 787. Cheapest Flights Within K Stops
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
nwill be in range[1, 100], with nodes labeled from0ton - 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]. kis 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:
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.
因为可以转乘一次,所以最少为200Input: 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次的情况下,从src到dst的价格最少。记mid为从src起飞能到的城市之一。原问题转化为最小化在不超过k-1次的情况下,从mid到dst的价格+src到mid的价格。即 minmid{Psrc−>mid,1+Pmid−>dst,k−1} 。可以用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