414周赛·第四题 - 3283. 吃掉所有兵需要的最多移动次数

题目链接 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)
posted @ 2024-09-09 01:49  WrRan  阅读(4)  评论(0编辑  收藏  举报