787. K 站中转内最便宜的航班
方法一:递归
class Solution:
def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int:
sdp = defaultdict(list)
for s,d,p in flights:
sdp[s].append([d,p])
@lru_cache(None)
def dfs(c, t):
if c == dst: return 0 # c 就是目标城市,票价为 0
if t > k: return inf # 中转次数 t > k 不可达
ans = inf
for d,p in sdp[c]:
ans = min(ans, dfs(d,t+1) + p)
return ans
res = dfs(src, 0)
return res if res != inf else -1
方法二:记忆化搜索
class Solution:
def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int:
sdp = defaultdict(list)
for s,d,p in flights:
sdp[s].append([d,p])
# @lru_cache(None)
def dfs(c, t):
if c == dst: return 0
if t > k: return inf
if memo[c][t]: return memo[c][t]
ans = inf
for d,p in sdp[c]:
ans = min(ans, dfs(d,t+1) + p)
memo[c][t] = ans
return ans
memo = [[0]*(k+1) for _ in range(n)]
res = dfs(src, 0)
return res if res != inf else -1
方法三:动态规划
表示从城市 出发,经过 次航班( 中转),到达城市 所需的最少花费。枚举直达 的 ,那么前 次航班到达 的花费 加上最后一次航班的花费 中的最小值,即为 。
即:
其中 表示从城市 到达城市 的航班,
由于最多中转
中的最小值。
注意到 只会从
下面的代码使用二维数组进行状态转移。
class Solution:
def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int:
f = [[inf] * n for _ in range(k+2)]
f[0][src] = 0
for t in range(1, k+2):
for s, d, cost in flights:
f[t][d] = min(f[t][d], f[t-1][s] + cost)
ans = min(f[t][dst] for t in range(1, k+2))
return -1 if ans == inf else ans
下面的代码使用两个一维数组进行状态转移。
class Solution:
def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, k: int) -> int:
f = [inf] * n
f[src] = 0
ans = inf
for t in range(1, k + 2):
g = [inf] * n
for s, d, cost in flights:
g[d] = min(g[d], f[s] + cost)
f = g
ans = min(ans, f[dst])
return -1 if ans == inf else ans