20241204: 2056. 棋盘上有效移动组合的数目

有一个 8 x 8 的棋盘,它包含 n 个棋子(棋子包括车,后和象三种)。给你一个长度为 n 的字符串数组 pieces ,其中 pieces[i] 表示第 i 个棋子的类型(车,后或象)。除此以外,还给你一个长度为 n 的二维整数数组 positions ,其中 positions[i] = [ri, ci] 表示第 i 个棋子现在在棋盘上的位置为 (ri, ci) ,棋盘下标从 1 开始。

棋盘上每个棋子都可以移动 至多一次 。每个棋子的移动中,首先选择移动的 方向 ,然后选择 移动的步数 ,同时你要确保移动过程中棋子不能移到棋盘以外的地方。棋子需按照以下规则移动:

  • 车可以 水平或者竖直 从 (r, c) 沿着方向 (r+1, c)(r-1, c)(r, c+1) 或者 (r, c-1) 移动。
  • 后可以 水平竖直或者斜对角 从 (r, c) 沿着方向 (r+1, c)(r-1, c)(r, c+1)(r, c-1)(r+1, c+1)(r+1, c-1)(r-1, c+1)(r-1, c-1) 移动。
  • 象可以 斜对角 从 (r, c) 沿着方向 (r+1, c+1)(r+1, c-1)(r-1, c+1)(r-1, c-1) 移动。

移动组合 包含所有棋子的 移动 。每一秒,每个棋子都沿着它们选择的方向往前移动 一步 ,直到它们到达目标位置。所有棋子从时刻 0 开始移动。如果在某个时刻,两个或者更多棋子占据了同一个格子,那么这个移动组合 不有效 。

请你返回 有效 移动组合的数目。

注意:

  • 初始时,不会有两个棋子 在 同一个位置 。
  • 有可能在一个移动组合中,有棋子不移动。
  • 如果两个棋子 直接相邻 且两个棋子下一秒要互相占据对方的位置,可以将它们在同一秒内 交换位置 。

 

 

复制代码
class Movement:
    def __init__(self, start_x, start_y, end_x, end_y, dx, dy):
        self.start_x = start_x
        self.start_y = start_y
        self.end_x = end_x
        self.end_y = end_y
        self.dx = dx
        self.dy = dy
        self.cur_x = start_x
        self.cur_y = start_y

    def reset(self):
        self.cur_x = self.start_x
        self.cur_y = self.start_y

    def stopped(self):
        return self.cur_x == self.end_x and self.cur_y == self.end_y

    def advance(self):
        if not self.stopped():
            self.cur_x += self.dx
            self.cur_y += self.dy

    def cross(self, other):
        # 每次判断是否相遇时需要重置 cur
        self.reset()
        other.reset()
        while not self.stopped() or not other.stopped():
            self.advance()
            other.advance()
            if self.cur_x == other.cur_x and self.cur_y == other.cur_y:
                return True
        return False

class Solution:
    def countCombinations(self, pieces: List[str], positions: List[List[int]]) -> int:
        rook_directions = [[1, 0], [-1, 0], [0, 1], [0, -1]] # 上下左右,车的移动方向
        bishop_directions = [[1, 1], [1, -1], [-1, 1], [-1, -1]] # 斜,象的移动
        queen_directions = rook_directions + bishop_directions # 后的移动
        n = len(pieces)
        res = 0
        stack = []

        def check(u):
            for v in range(u):
                if stack[u].cross(stack[v]):
                    return False
            return True

        def dfs(u):
            nonlocal res
            if u == n:
                res += 1
                return
            
            if pieces[u] == "rook":
                directions = rook_directions
            elif pieces[u] == "queen":
                directions = queen_directions
            elif pieces[u] == "bishop":
                directions = bishop_directions

            # 处理第 u 个棋子原地不动的情况
            stack.append(Movement(positions[u][0], positions[u][1], positions[u][0], positions[u][1], 0, 0))
            if check(u):
                dfs(u + 1)
            stack.pop()

            # 枚举第 u 个棋子在所有方向、所有步数的情况
            for dire in directions:
                for step in range(1, 8):
                    x = positions[u][0] + dire[0] * step
                    y = positions[u][1] + dire[1] * step
                    if x < 1 or x > 8 or y < 1 or y > 8:
                        break
                    stack.append(Movement(positions[u][0], positions[u][1], x, y, dire[0], dire[1]))
                    if check(u):
                        dfs(u + 1)
                    stack.pop()

        dfs(0)
        return res
复制代码

 

posted @   xiaoxinlong  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
AmazingCounters.com
点击右上角即可分享
微信分享提示