题目:787. K 站中转内最便宜的航班
两种方法:
方法一:
思路: 加权图的最短路径
1. 首先将航线转化为字典形式存储。(当前城市–下一城市–费用)
2. 建一个双向队列,元素为元组形式。(当前城市,src到当前城市的费用,中转次数)
3. 记录src到目的地dst的最小费用cheapest=1e6。(先设置为一个很大的数,这样在最后若cheapest=1e6,则说明没有从src到dst的路径,此时,返回-1)
4. 然后处理队列:
4.1 终止条件:K>2;
4.2 若遇到目的地,更新cheapest;
4.3 否则,若到某一中转站时,费用已经超过到底目的地的费用时,则果断放弃这一路线;只记录费用在cheapest内的中转站信息(中转站,src到中转站的费用,中转次数);
4.4 找出记录d中抵达终点站dst的记录。
注意点:d中元素为中转站时,会有好多条记录。如(r, 1500,2),(r,2000,2)。
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
"""
dic = collections.defaultdict(dict)
for u, v, w in flights:
dic[u][v] = w
d = collections.deque([(src, 0, 0)]) # 出发城市、src到出发城市需要的价格、中转次数
cheapest = 1e6
while d:
if d[0][2] > K:
break
u, w, n = d.popleft()
if u == dst:
cheapest = min(cheapest, w)
else:
for v in dic[u]:
if dic[u][v] + w < cheapest: # 及时停止
d.append((v, dic[u][v]+w, n+1))
while d:
u, w, n = d.popleft()
if u == dst:
cheapest = min(cheapest, w)
return cheapest if cheapest != 1e6 else -1
方法二:动态规划
思路: 采用动态规划来做,维护一个二维数组dp[k][i],其中dp[k][i]意思是中转k次到目的地为i的费用是多少。
1. 初始化dp[0][src]=0;
2. 则递推公式为:中转k次到达目的地i的费用等于=min(其他航线中转k次到达目的地,此次航线中转k-1次到达目的地i的前一站的费用+目的地i的前一站飞到目的地的费用)。
dp = [[1e9 for i in range(n)] for j in range(K+2)]
dp[0][src] = 0
for i in range(1,K+2):
for item in flights:
dp[i][item[1]] = min(dp[i][item[1]], dp[i-1][item[0]] + item[2])
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
"""
dp = [[1e9 for i in range(n)] for j in range(K+2)]
dp[0][src] = 0
for i in range(1,K+2):
for item in flights:
dp[i][item[1]] = min(dp[i][item[1]], dp[i-1][item[0]] + item[2])
cheapest = 1e9
for k in range(K+2):
cheapest = min(cheapest, dp[k][dst])
if cheapest >= 1e9:
return -1
else:
return cheapest