当前位置: 首页> 财经> 产业 > 中国能源建设集团有限公司招聘网_网红营销案例_关键字搜索软件_全球疫情今天最新消息

中国能源建设集团有限公司招聘网_网红营销案例_关键字搜索软件_全球疫情今天最新消息

时间:2025/8/29 3:35:24来源:https://blog.csdn.net/m0_69493801/article/details/144251672 浏览次数:0次
中国能源建设集团有限公司招聘网_网红营销案例_关键字搜索软件_全球疫情今天最新消息

执行结果:通过

题目: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 函数开始搜索。
    • 最后,返回计算得到的合法组合数量。

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

关键字:中国能源建设集团有限公司招聘网_网红营销案例_关键字搜索软件_全球疫情今天最新消息

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: