当前位置: 首页 > news >正文

Leetcode打卡:棋盘上有效移动组合的数目

执行结果:通过

题目: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 开始移动。如果在某个时刻,两个或者更多棋子占据了同一个格子,那么这个移动组合 不有效 。

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

注意:

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

示例 1:

输入:pieces = ["rook"], positions = [[1,1]]
输出:15
解释:上图展示了棋子所有可能的移动。

示例 2:

输入:pieces = ["queen"], positions = [[1,1]]
输出:22
解释:上图展示了棋子所有可能的移动。

示例 3:

输入:pieces = ["bishop"], positions = [[4,3]]
输出:12
解释:上图展示了棋子所有可能的移动。

示例 4:

输入:pieces = ["rook","rook"], positions = [[1,1],[8,8]]
输出:223
解释:每个车有 15 种移动,所以总共有 15 * 15 = 225 种移动组合。
但是,有两个是不有效的移动组合:
- 将两个车都移动到 (8, 1) ,会导致它们在同一个格子相遇。
- 将两个车都移动到 (1, 8) ,会导致它们在同一个格子相遇。
所以,总共有 225 - 2 = 223 种有效移动组合。
注意,有两种有效的移动组合,分别是一个车在 (1, 8) ,另一个车在 (8, 1) 。
即使棋盘状态是相同的,这两个移动组合被视为不同的,因为每个棋子移动操作是不相同的。

示例 5:

输入:pieces = ["queen","bishop"], positions = [[5,7],[3,4]]
输出:281
解释:总共有 12 * 24 = 288 种移动组合。
但是,有一些不有效的移动组合:
- 如果后停在 (6, 7) ,它会阻挡象到达 (6, 7) 或者 (7, 8) 。
- 如果后停在 (5, 6) ,它会阻挡象到达 (5, 6) ,(6, 7) 或者 (7, 8) 。
- 如果象停在 (5, 2) ,它会阻挡后到达 (5, 2) 或者 (5, 1) 。
在 288 个移动组合当中,281 个是有效的。

提示:

  • n == pieces.length
  • n == positions.length
  • 1 <= n <= 4
  • pieces 只包含字符串 "rook" ,"queen" 和 "bishop" 。
  • 棋盘上最多只有一个后。
  • 1 <= ri, ci <= 8
  • 每一个 positions[i] 互不相同。

代码以及解题思路

代码:

int rookDirections[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int bishopDirections[4][2] = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
int queenDirections[8][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};#define MAX_STACK_SIZE 1024typedef struct {int startX, startY, endX, endY, dx, dy, curX, curY;
} Movement;void initMovement(Movement *obj, int startX, int startY, int endX, int endY, int dx, int dy) {obj->startX = startX;obj->startY = startY;obj->endX = endX;obj->endY = endY;obj->dx = dx;obj->dy = dy;obj->curX = startX;obj->curY = startX;
}// Reset 重置棋子的当前位置
void reset(Movement *obj) {obj->curX = obj->startX;obj->curY = obj->startY;
}// Stopped 判断棋子是否停止
bool stopped(Movement *obj) {return obj->curX == obj->endX && obj->curY == obj->endY;
}// Advance 让棋子按照步长移动
void advance(Movement *obj) {if (!stopped(obj)) {obj->curX += obj->dx;obj->curY += obj->dy;}
}// Cross 判断两个棋子是否相遇
bool cross(Movement *m1, Movement *m2) {// 每次判断是否相遇时需要重置 curreset(m1);reset(m2);while (!stopped(m1) || !stopped(m2)) {advance(m1);advance(m2);if (m1->curX == m2->curX && m1->curY == m2->curY) {return true;}}return false;
}// Check 判断第 u 个棋子是否与之前的棋子发生相交
bool check(int u, Movement *stack) {for (int v = 0; v < u; v++) {Movement *m1 = &stack[u], *m2 = &stack[v];if (cross(m1, m2)) {return false;}}return true;
}void dfs(int u, char** pieces, int piecesSize, int** positions, Movement *stack, int *res) {if (u == piecesSize) {(*res)++;return;}// 处理第 u 个棋子原地不动的情况initMovement(&stack[u], positions[u][0], positions[u][1], positions[u][0], positions[u][1], 0, 0);if (check(u, stack)) {dfs(u + 1, pieces, piecesSize, positions, stack, res);}// 枚举第 u 个棋子在所有方向、所有步数的情况int (*directions)[2];int directionsSize = 0;if (!strcmp(pieces[u], "rook")) {directions = rookDirections;directionsSize = 4;} else if (!strcmp(pieces[u], "queen")) {directions = queenDirections;directionsSize = 8;} else {directions = bishopDirections;directionsSize = 4;}for (int i = 0; i < directionsSize; i++) {for (int j = 1; j < 8; j++) {int x = positions[u][0] + directions[i][0] * j;int y = positions[u][1] + directions[i][1] * j;if (x < 1 || x > 8 || y < 1 || y > 8) {break;}initMovement(&stack[u], positions[u][0], positions[u][1], x, y, directions[i][0], directions[i][1]);if (check(u, stack)) {dfs(u + 1, pieces, piecesSize, positions, stack, res);}}}
}int countCombinations(char** pieces, int piecesSize, int** positions, int positionsSize, int* positionsColSize) {int res = 0;Movement stack[MAX_STACK_SIZE];dfs(0, pieces, piecesSize, positions, stack, &res);return res;}

解题思路:

这个问题是关于在国际象棋棋盘上,给定一些棋子的类型和初始位置,计算它们移动到目标位置(这里假设目标位置是它们能移动到的任意合法位置,不一定是初始位置)的所有可能组合的数量,同时要求任意两个棋子在移动过程中不能相遇。棋子的类型包括车(rook)、象(bishop)和后(queen),每种棋子有不同的移动规则:

  • 车(rook)可以沿直线水平或垂直移动任意步数。
  • 象(bishop)可以沿对角线移动任意步数。
  • 后(queen)可以沿直线或对角线移动任意步数。

解题思路如下:

  1. 定义数据结构
    • 使用 Movement 结构体来表示棋子的移动状态,包括起始位置、结束位置、当前位置、以及移动的方向(dx, dy)。
    • 使用 rookDirectionsbishopDirections 和 queenDirections 数组来定义每种棋子的移动方向。
  2. 初始化
    • initMovement 函数用于初始化棋子的移动状态。
    • reset 函数用于重置棋子的当前位置到起始位置。
    • stopped 函数用于判断棋子是否已到达结束位置。
    • advance 函数用于按步长移动棋子。
  3. 判断相遇
    • cross 函数用于判断两个棋子在移动过程中是否会相遇。它首先重置两个棋子的当前位置,然后按照它们的移动规则逐步移动,如果在任何一步两个棋子的位置相同,则表示它们相遇。
  4. 检查合法性
    • check 函数用于检查在添加一个新的棋子移动方案后,该方案是否与之前的棋子移动方案发生冲突(即是否有棋子相遇)。
  5. 深度优先搜索(DFS)
    • dfs 函数是核心递归函数,用于枚举所有可能的棋子移动组合。
    • 它首先处理每个棋子原地不动的情况。
    • 然后,对于每种棋子和每个方向,它枚举棋子在该方向上移动1到7步(假设棋盘是8x8的)的所有可能情况。
    • 对于每种情况,如果它不与之前的棋子移动方案冲突,则递归地继续处理下一个棋子。
    • 当所有棋子都被处理完毕时,找到一个合法的组合,结果计数加一。
  6. 主函数
    • countCombinations 函数是程序的入口,它初始化结果变量和 Movement 栈,然后调用 dfs 函数开始搜索。
    • 最后,返回计算得到的合法组合数量。

通过这种方式,程序能够枚举所有可能的棋子移动组合,同时确保任意两个棋子在移动过程中不会相遇,从而计算出所有合法的组合数量。

http://www.lryc.cn/news/497464.html

相关文章:

  • 生产看板到底在看什么?
  • 12,攻防世界simple_php
  • 解决Jupyter Notebook无法转化为Pdf的问题(基于Typora非常实用)
  • 齐护机器人ModbusRTU RS485转TTL通信模块与ESP32 Arduino通信可Mixly的图形化编程Scratch图形化编程
  • python学习笔记15 python中的类
  • PMP–一、二、三模、冲刺–分类–10.沟通管理
  • android-studio开发第一个项目,并在设备上调试
  • springboot/ssm线上教育培训办公系统Java代码web项目在线课程作业源码
  • Spring 依赖 详解
  • 千益畅行,旅游卡有些什么优势?
  • Ubuntu24 cgroupv2导致rancher(k3s)启动失败的处理
  • 学习CSS第二天
  • 2021数学分析【南昌大学】
  • 单端和差分信号的接线法
  • 力扣-图论-2【算法学习day.52】
  • MySQL如何区分幻读和不可重复读
  • 界面控件Syncfusion Essential Studio®现在已完全支持 .NET 9
  • openEuler安装lsb_release
  • 统计数字字符个数
  • 44页PDF | 信息化战略规划标准框架方法论与实施方法(限免下载)
  • 计算机网络期末复习-part1-概述
  • A1228 php+Mysql旅游供需平台的设计与实现 导游接单 旅游订单 旅游分享网站 thinkphp框架 源码 配置 文档 全套资料
  • RabbitMQ消息可靠性保证机制5--消息幂等性处理
  • Claude3.5如何使用?
  • 力扣刷题TOP101:14.BM16 删除有序链表中重复的元素-II
  • 解决github网络慢的问题
  • docker及docker exec命令学习笔记
  • linux环境宝塔服务部署安装及介绍
  • 充分统计量(Sufficient Statistic)概念与应用: 中英双语
  • 基于Matlab计算机视觉的车道线识别与前车检测系统研究