題目連結 | 3283. 吃掉所有兵需要的最多移動次數 |
---|---|
思路 | 動態規劃 |
題解連結 | 相鄰相關排列型狀壓 DP(Python/Java/C++/Go) |
關鍵點 | 狀態壓縮DP 1. 預處理-如何得到“最少移動步數”-BFS & 轉換為“位於\(positions[i]\)的馬到\((x, y)\)的步數” 2. 如何子集列舉-位運算(掩碼) 3. Alice/Bob目的不同 - 掩碼補集奇偶性 |
時間複雜度 | \(O(n L^2 + n^2 2^n)\) |
空間複雜度 | \(O(n L^2 + n 2^n)\) |
程式碼實現:
DIRS = ((2, 1), (1, 2), (-1, 2), (-2, 1), (-2, -1), (-1, -2), (1, -2), (2, -1))
class Solution:
def maxMoves(self, kx: int, ky: int, positions: List[List[int]]) -> int:
n = len(positions)
# 計算馬到兵的步數,等價於計算兵到其餘格子的步數
distances = [[[-1] * 50 for _ in range(50)] for _ in range(n)]
# 下列迴圈時間複雜度為 O(nL^2)
for d, (px, py) in zip(distances, positions):
d[px][py] = 0
q = [(px, py)]
step = 1
while q:
new_q = []
for x, y in q:
for dx, dy in DIRS:
nx, ny = x + dx, y + dy
if 0 <= nx < 50 and 0 <= ny < 50 and d[nx][ny] < 0:
d[nx][ny] = step
new_q.append((nx, ny))
q = new_q
step += 1
positions.append((kx, ky))
u = (1 << n) - 1
# 呼叫複雜度為 O(n^2 2^n)
@cache
def dfs(i: int, mask: int) -> int:
if mask == 0:
return 0
odd = (u ^ mask).bit_count() % 2
answer = inf if odd else 0
op = min if odd else max
x, y = positions[i]
for j, d in enumerate(distances):
if mask >> j & 1:
answer = op(answer, dfs(j, mask ^ (1 << j)) + d[x][y])
return answer
return dfs(n, u)