From c5228161fed4c639b30abb9f57895c302a8d4e66 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Fri, 22 Nov 2024 15:30:35 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.2056 No.2056.Number of Valid Move Combinations On Chessboard --- .../README.md | 482 +++++++++++++++++- .../README_EN.md | 482 +++++++++++++++++- .../Solution.cpp | 98 ++++ .../Solution.go | 99 ++++ .../Solution.java | 98 ++++ .../Solution.py | 60 +++ .../Solution.ts | 108 ++++ 7 files changed, 1419 insertions(+), 8 deletions(-) create mode 100644 solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.cpp create mode 100644 solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.go create mode 100644 solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.java create mode 100644 solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.py create mode 100644 solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.ts diff --git a/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/README.md b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/README.md index 4957f6fdc81eb..5dc8e5547bfac 100644 --- a/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/README.md +++ b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/README.md @@ -126,32 +126,506 @@ tags: -### 方法一 +### 方法一:DFS + +题目最多只有 $4$ 个棋子,每个棋子的移动方向最多有 $8$ 种,我们可以考虑使用 DFS 搜索所有的移动组合。 + +我们按照顺序依次枚举每个棋子,对于每个棋子,我们可以选择不移动,或者按照规则移动,用数组 $\textit{dist}[i]$ 记录第 $i$ 个棋子的移动情况,其中 $\textit{dist}[i][x][y]$ 表示第 $i$ 个棋子经过坐标 $(x, y)$ 时的时间,用数组 $\textit{end}[i]$ 记录第 $i$ 个棋子的终点坐标和时间。在搜索时,我们需要分别判断当前棋子是否可以停止移动,以及当前棋子是否可以继续在当前方向移动。 + +我们定义方法 $\text{checkStop}(i, x, y, t)$ 判断第 $i$ 个棋子是否在时间 $t$ 时停在坐标 $(x, y)$,如果对于此前的所有棋子 $j$,都有 $\textit{dist}[j][x][y] < t$,那么第 $i$ 个棋子可以停止移动。 + +另外,我们定义方法 $\text{checkPass}(i, x, y, t)$ 判断第 $i$ 个棋子是否可以在时间 $t$ 时经过坐标 $(x, y)$。如果此前有其它棋子 $j$ 也在时间 $t$ 经过坐标 $(x, y)$,或者有其它棋子 $j$ 停在 $(x, y)$,且时间不超过 $t$,那么第 $i$ 个棋子不能在时间 $t$ 时经过坐标 $(x, y)$。 + +时间复杂度 $O((n \times M)^n)$,空间复杂度 $O(n \times M)$。其中 $n$ 是棋子的数量,而 $M$ 是每个棋子的移动范围。 #### Python3 ```python - +rook_dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)] +bishop_dirs = [(1, 1), (1, -1), (-1, 1), (-1, -1)] +queue_dirs = rook_dirs + bishop_dirs + + +def get_dirs(piece: str) -> List[Tuple[int, int]]: + match piece[0]: + case "r": + return rook_dirs + case "b": + return bishop_dirs + case _: + return queue_dirs + + +class Solution: + def countCombinations(self, pieces: List[str], positions: List[List[int]]) -> int: + def check_stop(i: int, x: int, y: int, t: int) -> bool: + return all(dist[j][x][y] < t for j in range(i)) + + def check_pass(i: int, x: int, y: int, t: int) -> bool: + for j in range(i): + if dist[j][x][y] == t: + return False + if end[j][0] == x and end[j][1] == y and end[j][2] <= t: + return False + return True + + def dfs(i: int) -> None: + if i >= n: + nonlocal ans + ans += 1 + return + x, y = positions[i] + dist[i][:] = [[-1] * m for _ in range(m)] + dist[i][x][y] = 0 + end[i] = (x, y, 0) + if check_stop(i, x, y, 0): + dfs(i + 1) + dirs = get_dirs(pieces[i]) + for dx, dy in dirs: + dist[i][:] = [[-1] * m for _ in range(m)] + dist[i][x][y] = 0 + nx, ny, nt = x + dx, y + dy, 1 + while 1 <= nx < m and 1 <= ny < m and check_pass(i, nx, ny, nt): + dist[i][nx][ny] = nt + end[i] = (nx, ny, nt) + if check_stop(i, nx, ny, nt): + dfs(i + 1) + nx += dx + ny += dy + nt += 1 + + n = len(pieces) + m = 9 + dist = [[[-1] * m for _ in range(m)] for _ in range(n)] + end = [(0, 0, 0) for _ in range(n)] + ans = 0 + dfs(0) + return ans ``` #### Java ```java - +class Solution { + int n, m = 9, ans; + int[][][] dist; + int[][] end; + String[] pieces; + int[][] positions; + int[][] rookDirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + int[][] bishopDirs = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + int[][] queenDirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + + public int countCombinations(String[] pieces, int[][] positions) { + n = pieces.length; + dist = new int[n][m][m]; + end = new int[n][3]; + ans = 0; + this.pieces = pieces; + this.positions = positions; + + dfs(0); + return ans; + } + + private void dfs(int i) { + if (i >= n) { + ans++; + return; + } + + int x = positions[i][0], y = positions[i][1]; + resetDist(i); + dist[i][x][y] = 0; + end[i] = new int[] {x, y, 0}; + + if (checkStop(i, x, y, 0)) { + dfs(i + 1); + } + + int[][] dirs = getDirs(pieces[i]); + for (int[] dir : dirs) { + resetDist(i); + dist[i][x][y] = 0; + int nx = x + dir[0], ny = y + dir[1], nt = 1; + + while (isValid(nx, ny) && checkPass(i, nx, ny, nt)) { + dist[i][nx][ny] = nt; + end[i] = new int[] {nx, ny, nt}; + if (checkStop(i, nx, ny, nt)) { + dfs(i + 1); + } + nx += dir[0]; + ny += dir[1]; + nt++; + } + } + } + + private void resetDist(int i) { + for (int j = 0; j < m; j++) { + for (int k = 0; k < m; k++) { + dist[i][j][k] = -1; + } + } + } + + private boolean checkStop(int i, int x, int y, int t) { + for (int j = 0; j < i; j++) { + if (dist[j][x][y] >= t) { + return false; + } + } + return true; + } + + private boolean checkPass(int i, int x, int y, int t) { + for (int j = 0; j < i; j++) { + if (dist[j][x][y] == t) { + return false; + } + if (end[j][0] == x && end[j][1] == y && end[j][2] <= t) { + return false; + } + } + return true; + } + + private boolean isValid(int x, int y) { + return x >= 1 && x < m && y >= 1 && y < m; + } + + private int[][] getDirs(String piece) { + char c = piece.charAt(0); + return switch (c) { + case 'r' -> rookDirs; + case 'b' -> bishopDirs; + default -> queenDirs; + }; + } +} ``` #### C++ ```cpp - +class Solution { +public: + int countCombinations(vector& pieces, vector>& positions) { + int n = pieces.size(); + const int m = 9; + int ans = 0; + + vector>> dist(n, vector>(m, vector(m, -1))); + vector> end(n, vector(3)); + + const int rookDirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + const int bishopDirs[4][2] = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + const int queenDirs[8][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + + auto resetDist = [&](int i) { + for (int j = 0; j < m; j++) { + for (int k = 0; k < m; k++) { + dist[i][j][k] = -1; + } + } + }; + + auto checkStop = [&](int i, int x, int y, int t) -> bool { + for (int j = 0; j < i; j++) { + if (dist[j][x][y] >= t) { + return false; + } + } + return true; + }; + + auto checkPass = [&](int i, int x, int y, int t) -> bool { + for (int j = 0; j < i; j++) { + if (dist[j][x][y] == t) { + return false; + } + if (end[j][0] == x && end[j][1] == y && end[j][2] <= t) { + return false; + } + } + return true; + }; + + auto isValid = [&](int x, int y) -> bool { + return x >= 1 && x < m && y >= 1 && y < m; + }; + + auto getDirs = [&](const string& piece) -> const int(*)[2] { + char c = piece[0]; + if (c == 'r') { + return rookDirs; + } + if (c == 'b') { + return bishopDirs; + } + return queenDirs; + }; + + auto dfs = [&](auto&& dfs, int i) -> void { + if (i >= n) { + ans++; + return; + } + + int x = positions[i][0], y = positions[i][1]; + resetDist(i); + dist[i][x][y] = 0; + end[i] = {x, y, 0}; + + if (checkStop(i, x, y, 0)) { + dfs(dfs, i + 1); + } + + const int(*dirs)[2] = getDirs(pieces[i]); + int dirsSize = (pieces[i][0] == 'q') ? 8 : 4; + + for (int d = 0; d < dirsSize; d++) { + resetDist(i); + dist[i][x][y] = 0; + int nx = x + dirs[d][0], ny = y + dirs[d][1], nt = 1; + + while (isValid(nx, ny) && checkPass(i, nx, ny, nt)) { + dist[i][nx][ny] = nt; + end[i] = {nx, ny, nt}; + if (checkStop(i, nx, ny, nt)) { + dfs(dfs, i + 1); + } + nx += dirs[d][0]; + ny += dirs[d][1]; + nt++; + } + } + }; + + dfs(dfs, 0); + return ans; + } +}; ``` #### Go ```go +func countCombinations(pieces []string, positions [][]int) (ans int) { + n := len(pieces) + m := 9 + dist := make([][][]int, n) + for i := range dist { + dist[i] = make([][]int, m) + for j := range dist[i] { + dist[i][j] = make([]int, m) + } + } + + end := make([][3]int, n) + + rookDirs := [][2]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}} + bishopDirs := [][2]int{{1, 1}, {1, -1}, {-1, 1}, {-1, -1}} + queenDirs := [][2]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}} + + resetDist := func(i int) { + for j := 0; j < m; j++ { + for k := 0; k < m; k++ { + dist[i][j][k] = -1 + } + } + } + + checkStop := func(i, x, y, t int) bool { + for j := 0; j < i; j++ { + if dist[j][x][y] >= t { + return false + } + } + return true + } + + checkPass := func(i, x, y, t int) bool { + for j := 0; j < i; j++ { + if dist[j][x][y] == t { + return false + } + if end[j][0] == x && end[j][1] == y && end[j][2] <= t { + return false + } + } + return true + } + + isValid := func(x, y int) bool { + return x >= 1 && x < m && y >= 1 && y < m + } + + getDirs := func(piece string) [][2]int { + switch piece[0] { + case 'r': + return rookDirs + case 'b': + return bishopDirs + default: + return queenDirs + } + } + + var dfs func(i int) + dfs = func(i int) { + if i >= n { + ans++ + return + } + + x, y := positions[i][0], positions[i][1] + resetDist(i) + dist[i][x][y] = 0 + end[i] = [3]int{x, y, 0} + + if checkStop(i, x, y, 0) { + dfs(i + 1) + } + + dirs := getDirs(pieces[i]) + for _, dir := range dirs { + resetDist(i) + dist[i][x][y] = 0 + nx, ny, nt := x+dir[0], y+dir[1], 1 + + for isValid(nx, ny) && checkPass(i, nx, ny, nt) { + dist[i][nx][ny] = nt + end[i] = [3]int{nx, ny, nt} + if checkStop(i, nx, ny, nt) { + dfs(i + 1) + } + nx += dir[0] + ny += dir[1] + nt++ + } + } + } + + dfs(0) + return +} +``` +#### TypeScript + +```ts +const rookDirs: [number, number][] = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], +]; +const bishopDirs: [number, number][] = [ + [1, 1], + [1, -1], + [-1, 1], + [-1, -1], +]; +const queenDirs = [...rookDirs, ...bishopDirs]; + +function countCombinations(pieces: string[], positions: number[][]): number { + const n = pieces.length; + const m = 9; + let ans = 0; + + const dist = Array.from({ length: n }, () => + Array.from({ length: m }, () => Array(m).fill(-1)), + ); + + const end: [number, number, number][] = Array(n).fill([0, 0, 0]); + + const resetDist = (i: number) => { + for (let j = 0; j < m; j++) { + for (let k = 0; k < m; k++) { + dist[i][j][k] = -1; + } + } + }; + + const checkStop = (i: number, x: number, y: number, t: number): boolean => { + for (let j = 0; j < i; j++) { + if (dist[j][x][y] >= t) { + return false; + } + } + return true; + }; + + const checkPass = (i: number, x: number, y: number, t: number): boolean => { + for (let j = 0; j < i; j++) { + if (dist[j][x][y] === t) { + return false; + } + if (end[j][0] === x && end[j][1] === y && end[j][2] <= t) { + return false; + } + } + return true; + }; + + const isValid = (x: number, y: number): boolean => { + return x >= 1 && x < m && y >= 1 && y < m; + }; + + const getDirs = (piece: string): [number, number][] => { + switch (piece[0]) { + case 'r': + return rookDirs; + case 'b': + return bishopDirs; + default: + return queenDirs; + } + }; + + const dfs = (i: number) => { + if (i >= n) { + ans++; + return; + } + + const [x, y] = positions[i]; + resetDist(i); + dist[i][x][y] = 0; + end[i] = [x, y, 0]; + + if (checkStop(i, x, y, 0)) { + dfs(i + 1); + } + + const dirs = getDirs(pieces[i]); + for (const [dx, dy] of dirs) { + resetDist(i); + dist[i][x][y] = 0; + let nx = x + dx, + ny = y + dy, + nt = 1; + + while (isValid(nx, ny) && checkPass(i, nx, ny, nt)) { + dist[i][nx][ny] = nt; + end[i] = [nx, ny, nt]; + if (checkStop(i, nx, ny, nt)) { + dfs(i + 1); + } + nx += dx; + ny += dy; + nt++; + } + } + }; + + dfs(0); + return ans; +} ``` diff --git a/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/README_EN.md b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/README_EN.md index 808734a1bd51a..9f32a7e97ab97 100644 --- a/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/README_EN.md +++ b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/README_EN.md @@ -87,32 +87,506 @@ tags: -### Solution 1 +### Solution 1: DFS + +The problem has at most $4$ pieces, and each piece can move in up to $8$ directions. We can consider using DFS to search all possible move combinations. + +We enumerate each piece in order. For each piece, we can choose not to move or move according to the rules. We use an array $\textit{dist}[i]$ to record the movement of the $i$-th piece, where $\textit{dist}[i][x][y]$ represents the time when the $i$-th piece passes through the coordinate $(x, y)$. We use an array $\textit{end}[i]$ to record the endpoint coordinates and time of the $i$-th piece. During the search, we need to determine whether the current piece can stop moving and whether it can continue moving in the current direction. + +We define a method $\text{checkStop}(i, x, y, t)$ to determine whether the $i$-th piece can stop at coordinate $(x, y)$ at time $t$. If for all previous pieces $j$, $\textit{dist}[j][x][y] < t$, then the $i$-th piece can stop moving. + +Additionally, we define a method $\text{checkPass}(i, x, y, t)$ to determine whether the $i$-th piece can pass through coordinate $(x, y)$ at time $t$. If any other piece $j$ also passes through coordinate $(x, y)$ at time $t$, or if any other piece $j$ stops at $(x, y)$ and the time does not exceed $t$, then the $i$-th piece cannot pass through coordinate $(x, y)$ at time $t$. + +The time complexity is $O((n \times M)^n)$, and the space complexity is $O(n \times M)$. Here, $n$ is the number of pieces, and $M$ is the movement range of each piece. #### Python3 ```python - +rook_dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)] +bishop_dirs = [(1, 1), (1, -1), (-1, 1), (-1, -1)] +queue_dirs = rook_dirs + bishop_dirs + + +def get_dirs(piece: str) -> List[Tuple[int, int]]: + match piece[0]: + case "r": + return rook_dirs + case "b": + return bishop_dirs + case _: + return queue_dirs + + +class Solution: + def countCombinations(self, pieces: List[str], positions: List[List[int]]) -> int: + def check_stop(i: int, x: int, y: int, t: int) -> bool: + return all(dist[j][x][y] < t for j in range(i)) + + def check_pass(i: int, x: int, y: int, t: int) -> bool: + for j in range(i): + if dist[j][x][y] == t: + return False + if end[j][0] == x and end[j][1] == y and end[j][2] <= t: + return False + return True + + def dfs(i: int) -> None: + if i >= n: + nonlocal ans + ans += 1 + return + x, y = positions[i] + dist[i][:] = [[-1] * m for _ in range(m)] + dist[i][x][y] = 0 + end[i] = (x, y, 0) + if check_stop(i, x, y, 0): + dfs(i + 1) + dirs = get_dirs(pieces[i]) + for dx, dy in dirs: + dist[i][:] = [[-1] * m for _ in range(m)] + dist[i][x][y] = 0 + nx, ny, nt = x + dx, y + dy, 1 + while 1 <= nx < m and 1 <= ny < m and check_pass(i, nx, ny, nt): + dist[i][nx][ny] = nt + end[i] = (nx, ny, nt) + if check_stop(i, nx, ny, nt): + dfs(i + 1) + nx += dx + ny += dy + nt += 1 + + n = len(pieces) + m = 9 + dist = [[[-1] * m for _ in range(m)] for _ in range(n)] + end = [(0, 0, 0) for _ in range(n)] + ans = 0 + dfs(0) + return ans ``` #### Java ```java - +class Solution { + int n, m = 9, ans; + int[][][] dist; + int[][] end; + String[] pieces; + int[][] positions; + int[][] rookDirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + int[][] bishopDirs = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + int[][] queenDirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + + public int countCombinations(String[] pieces, int[][] positions) { + n = pieces.length; + dist = new int[n][m][m]; + end = new int[n][3]; + ans = 0; + this.pieces = pieces; + this.positions = positions; + + dfs(0); + return ans; + } + + private void dfs(int i) { + if (i >= n) { + ans++; + return; + } + + int x = positions[i][0], y = positions[i][1]; + resetDist(i); + dist[i][x][y] = 0; + end[i] = new int[] {x, y, 0}; + + if (checkStop(i, x, y, 0)) { + dfs(i + 1); + } + + int[][] dirs = getDirs(pieces[i]); + for (int[] dir : dirs) { + resetDist(i); + dist[i][x][y] = 0; + int nx = x + dir[0], ny = y + dir[1], nt = 1; + + while (isValid(nx, ny) && checkPass(i, nx, ny, nt)) { + dist[i][nx][ny] = nt; + end[i] = new int[] {nx, ny, nt}; + if (checkStop(i, nx, ny, nt)) { + dfs(i + 1); + } + nx += dir[0]; + ny += dir[1]; + nt++; + } + } + } + + private void resetDist(int i) { + for (int j = 0; j < m; j++) { + for (int k = 0; k < m; k++) { + dist[i][j][k] = -1; + } + } + } + + private boolean checkStop(int i, int x, int y, int t) { + for (int j = 0; j < i; j++) { + if (dist[j][x][y] >= t) { + return false; + } + } + return true; + } + + private boolean checkPass(int i, int x, int y, int t) { + for (int j = 0; j < i; j++) { + if (dist[j][x][y] == t) { + return false; + } + if (end[j][0] == x && end[j][1] == y && end[j][2] <= t) { + return false; + } + } + return true; + } + + private boolean isValid(int x, int y) { + return x >= 1 && x < m && y >= 1 && y < m; + } + + private int[][] getDirs(String piece) { + char c = piece.charAt(0); + return switch (c) { + case 'r' -> rookDirs; + case 'b' -> bishopDirs; + default -> queenDirs; + }; + } +} ``` #### C++ ```cpp - +class Solution { +public: + int countCombinations(vector& pieces, vector>& positions) { + int n = pieces.size(); + const int m = 9; + int ans = 0; + + vector>> dist(n, vector>(m, vector(m, -1))); + vector> end(n, vector(3)); + + const int rookDirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + const int bishopDirs[4][2] = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + const int queenDirs[8][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + + auto resetDist = [&](int i) { + for (int j = 0; j < m; j++) { + for (int k = 0; k < m; k++) { + dist[i][j][k] = -1; + } + } + }; + + auto checkStop = [&](int i, int x, int y, int t) -> bool { + for (int j = 0; j < i; j++) { + if (dist[j][x][y] >= t) { + return false; + } + } + return true; + }; + + auto checkPass = [&](int i, int x, int y, int t) -> bool { + for (int j = 0; j < i; j++) { + if (dist[j][x][y] == t) { + return false; + } + if (end[j][0] == x && end[j][1] == y && end[j][2] <= t) { + return false; + } + } + return true; + }; + + auto isValid = [&](int x, int y) -> bool { + return x >= 1 && x < m && y >= 1 && y < m; + }; + + auto getDirs = [&](const string& piece) -> const int(*)[2] { + char c = piece[0]; + if (c == 'r') { + return rookDirs; + } + if (c == 'b') { + return bishopDirs; + } + return queenDirs; + }; + + auto dfs = [&](auto&& dfs, int i) -> void { + if (i >= n) { + ans++; + return; + } + + int x = positions[i][0], y = positions[i][1]; + resetDist(i); + dist[i][x][y] = 0; + end[i] = {x, y, 0}; + + if (checkStop(i, x, y, 0)) { + dfs(dfs, i + 1); + } + + const int(*dirs)[2] = getDirs(pieces[i]); + int dirsSize = (pieces[i][0] == 'q') ? 8 : 4; + + for (int d = 0; d < dirsSize; d++) { + resetDist(i); + dist[i][x][y] = 0; + int nx = x + dirs[d][0], ny = y + dirs[d][1], nt = 1; + + while (isValid(nx, ny) && checkPass(i, nx, ny, nt)) { + dist[i][nx][ny] = nt; + end[i] = {nx, ny, nt}; + if (checkStop(i, nx, ny, nt)) { + dfs(dfs, i + 1); + } + nx += dirs[d][0]; + ny += dirs[d][1]; + nt++; + } + } + }; + + dfs(dfs, 0); + return ans; + } +}; ``` #### Go ```go +func countCombinations(pieces []string, positions [][]int) (ans int) { + n := len(pieces) + m := 9 + dist := make([][][]int, n) + for i := range dist { + dist[i] = make([][]int, m) + for j := range dist[i] { + dist[i][j] = make([]int, m) + } + } + + end := make([][3]int, n) + + rookDirs := [][2]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}} + bishopDirs := [][2]int{{1, 1}, {1, -1}, {-1, 1}, {-1, -1}} + queenDirs := [][2]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}} + + resetDist := func(i int) { + for j := 0; j < m; j++ { + for k := 0; k < m; k++ { + dist[i][j][k] = -1 + } + } + } + + checkStop := func(i, x, y, t int) bool { + for j := 0; j < i; j++ { + if dist[j][x][y] >= t { + return false + } + } + return true + } + + checkPass := func(i, x, y, t int) bool { + for j := 0; j < i; j++ { + if dist[j][x][y] == t { + return false + } + if end[j][0] == x && end[j][1] == y && end[j][2] <= t { + return false + } + } + return true + } + + isValid := func(x, y int) bool { + return x >= 1 && x < m && y >= 1 && y < m + } + + getDirs := func(piece string) [][2]int { + switch piece[0] { + case 'r': + return rookDirs + case 'b': + return bishopDirs + default: + return queenDirs + } + } + + var dfs func(i int) + dfs = func(i int) { + if i >= n { + ans++ + return + } + + x, y := positions[i][0], positions[i][1] + resetDist(i) + dist[i][x][y] = 0 + end[i] = [3]int{x, y, 0} + + if checkStop(i, x, y, 0) { + dfs(i + 1) + } + + dirs := getDirs(pieces[i]) + for _, dir := range dirs { + resetDist(i) + dist[i][x][y] = 0 + nx, ny, nt := x+dir[0], y+dir[1], 1 + + for isValid(nx, ny) && checkPass(i, nx, ny, nt) { + dist[i][nx][ny] = nt + end[i] = [3]int{nx, ny, nt} + if checkStop(i, nx, ny, nt) { + dfs(i + 1) + } + nx += dir[0] + ny += dir[1] + nt++ + } + } + } + + dfs(0) + return +} +``` +#### TypeScript + +```ts +const rookDirs: [number, number][] = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], +]; +const bishopDirs: [number, number][] = [ + [1, 1], + [1, -1], + [-1, 1], + [-1, -1], +]; +const queenDirs = [...rookDirs, ...bishopDirs]; + +function countCombinations(pieces: string[], positions: number[][]): number { + const n = pieces.length; + const m = 9; + let ans = 0; + + const dist = Array.from({ length: n }, () => + Array.from({ length: m }, () => Array(m).fill(-1)), + ); + + const end: [number, number, number][] = Array(n).fill([0, 0, 0]); + + const resetDist = (i: number) => { + for (let j = 0; j < m; j++) { + for (let k = 0; k < m; k++) { + dist[i][j][k] = -1; + } + } + }; + + const checkStop = (i: number, x: number, y: number, t: number): boolean => { + for (let j = 0; j < i; j++) { + if (dist[j][x][y] >= t) { + return false; + } + } + return true; + }; + + const checkPass = (i: number, x: number, y: number, t: number): boolean => { + for (let j = 0; j < i; j++) { + if (dist[j][x][y] === t) { + return false; + } + if (end[j][0] === x && end[j][1] === y && end[j][2] <= t) { + return false; + } + } + return true; + }; + + const isValid = (x: number, y: number): boolean => { + return x >= 1 && x < m && y >= 1 && y < m; + }; + + const getDirs = (piece: string): [number, number][] => { + switch (piece[0]) { + case 'r': + return rookDirs; + case 'b': + return bishopDirs; + default: + return queenDirs; + } + }; + + const dfs = (i: number) => { + if (i >= n) { + ans++; + return; + } + + const [x, y] = positions[i]; + resetDist(i); + dist[i][x][y] = 0; + end[i] = [x, y, 0]; + + if (checkStop(i, x, y, 0)) { + dfs(i + 1); + } + + const dirs = getDirs(pieces[i]); + for (const [dx, dy] of dirs) { + resetDist(i); + dist[i][x][y] = 0; + let nx = x + dx, + ny = y + dy, + nt = 1; + + while (isValid(nx, ny) && checkPass(i, nx, ny, nt)) { + dist[i][nx][ny] = nt; + end[i] = [nx, ny, nt]; + if (checkStop(i, nx, ny, nt)) { + dfs(i + 1); + } + nx += dx; + ny += dy; + nt++; + } + } + }; + + dfs(0); + return ans; +} ``` diff --git a/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.cpp b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.cpp new file mode 100644 index 0000000000000..9ff847a0a66a7 --- /dev/null +++ b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.cpp @@ -0,0 +1,98 @@ +class Solution { +public: + int countCombinations(vector& pieces, vector>& positions) { + int n = pieces.size(); + const int m = 9; + int ans = 0; + + vector>> dist(n, vector>(m, vector(m, -1))); + vector> end(n, vector(3)); + + const int rookDirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + const int bishopDirs[4][2] = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + const int queenDirs[8][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + + auto resetDist = [&](int i) { + for (int j = 0; j < m; j++) { + for (int k = 0; k < m; k++) { + dist[i][j][k] = -1; + } + } + }; + + auto checkStop = [&](int i, int x, int y, int t) -> bool { + for (int j = 0; j < i; j++) { + if (dist[j][x][y] >= t) { + return false; + } + } + return true; + }; + + auto checkPass = [&](int i, int x, int y, int t) -> bool { + for (int j = 0; j < i; j++) { + if (dist[j][x][y] == t) { + return false; + } + if (end[j][0] == x && end[j][1] == y && end[j][2] <= t) { + return false; + } + } + return true; + }; + + auto isValid = [&](int x, int y) -> bool { + return x >= 1 && x < m && y >= 1 && y < m; + }; + + auto getDirs = [&](const string& piece) -> const int(*)[2] { + char c = piece[0]; + if (c == 'r') { + return rookDirs; + } + if (c == 'b') { + return bishopDirs; + } + return queenDirs; + }; + + auto dfs = [&](auto&& dfs, int i) -> void { + if (i >= n) { + ans++; + return; + } + + int x = positions[i][0], y = positions[i][1]; + resetDist(i); + dist[i][x][y] = 0; + end[i] = {x, y, 0}; + + if (checkStop(i, x, y, 0)) { + dfs(dfs, i + 1); + } + + const int(*dirs)[2] = getDirs(pieces[i]); + int dirsSize = (pieces[i][0] == 'q') ? 8 : 4; + + for (int d = 0; d < dirsSize; d++) { + resetDist(i); + dist[i][x][y] = 0; + int nx = x + dirs[d][0], ny = y + dirs[d][1], nt = 1; + + while (isValid(nx, ny) && checkPass(i, nx, ny, nt)) { + dist[i][nx][ny] = nt; + end[i] = {nx, ny, nt}; + if (checkStop(i, nx, ny, nt)) { + dfs(dfs, i + 1); + } + nx += dirs[d][0]; + ny += dirs[d][1]; + nt++; + } + } + }; + + dfs(dfs, 0); + return ans; + } +}; diff --git a/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.go b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.go new file mode 100644 index 0000000000000..187044f43be7b --- /dev/null +++ b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.go @@ -0,0 +1,99 @@ +func countCombinations(pieces []string, positions [][]int) (ans int) { + n := len(pieces) + m := 9 + dist := make([][][]int, n) + for i := range dist { + dist[i] = make([][]int, m) + for j := range dist[i] { + dist[i][j] = make([]int, m) + } + } + + end := make([][3]int, n) + + rookDirs := [][2]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}} + bishopDirs := [][2]int{{1, 1}, {1, -1}, {-1, 1}, {-1, -1}} + queenDirs := [][2]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}} + + resetDist := func(i int) { + for j := 0; j < m; j++ { + for k := 0; k < m; k++ { + dist[i][j][k] = -1 + } + } + } + + checkStop := func(i, x, y, t int) bool { + for j := 0; j < i; j++ { + if dist[j][x][y] >= t { + return false + } + } + return true + } + + checkPass := func(i, x, y, t int) bool { + for j := 0; j < i; j++ { + if dist[j][x][y] == t { + return false + } + if end[j][0] == x && end[j][1] == y && end[j][2] <= t { + return false + } + } + return true + } + + isValid := func(x, y int) bool { + return x >= 1 && x < m && y >= 1 && y < m + } + + getDirs := func(piece string) [][2]int { + switch piece[0] { + case 'r': + return rookDirs + case 'b': + return bishopDirs + default: + return queenDirs + } + } + + var dfs func(i int) + dfs = func(i int) { + if i >= n { + ans++ + return + } + + x, y := positions[i][0], positions[i][1] + resetDist(i) + dist[i][x][y] = 0 + end[i] = [3]int{x, y, 0} + + if checkStop(i, x, y, 0) { + dfs(i + 1) + } + + dirs := getDirs(pieces[i]) + for _, dir := range dirs { + resetDist(i) + dist[i][x][y] = 0 + nx, ny, nt := x+dir[0], y+dir[1], 1 + + for isValid(nx, ny) && checkPass(i, nx, ny, nt) { + dist[i][nx][ny] = nt + end[i] = [3]int{nx, ny, nt} + if checkStop(i, nx, ny, nt) { + dfs(i + 1) + } + nx += dir[0] + ny += dir[1] + nt++ + } + } + } + + dfs(0) + return +} diff --git a/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.java b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.java new file mode 100644 index 0000000000000..f16ddb83adc82 --- /dev/null +++ b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.java @@ -0,0 +1,98 @@ +class Solution { + int n, m = 9, ans; + int[][][] dist; + int[][] end; + String[] pieces; + int[][] positions; + int[][] rookDirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + int[][] bishopDirs = {{1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + int[][] queenDirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; + + public int countCombinations(String[] pieces, int[][] positions) { + n = pieces.length; + dist = new int[n][m][m]; + end = new int[n][3]; + ans = 0; + this.pieces = pieces; + this.positions = positions; + + dfs(0); + return ans; + } + + private void dfs(int i) { + if (i >= n) { + ans++; + return; + } + + int x = positions[i][0], y = positions[i][1]; + resetDist(i); + dist[i][x][y] = 0; + end[i] = new int[] {x, y, 0}; + + if (checkStop(i, x, y, 0)) { + dfs(i + 1); + } + + int[][] dirs = getDirs(pieces[i]); + for (int[] dir : dirs) { + resetDist(i); + dist[i][x][y] = 0; + int nx = x + dir[0], ny = y + dir[1], nt = 1; + + while (isValid(nx, ny) && checkPass(i, nx, ny, nt)) { + dist[i][nx][ny] = nt; + end[i] = new int[] {nx, ny, nt}; + if (checkStop(i, nx, ny, nt)) { + dfs(i + 1); + } + nx += dir[0]; + ny += dir[1]; + nt++; + } + } + } + + private void resetDist(int i) { + for (int j = 0; j < m; j++) { + for (int k = 0; k < m; k++) { + dist[i][j][k] = -1; + } + } + } + + private boolean checkStop(int i, int x, int y, int t) { + for (int j = 0; j < i; j++) { + if (dist[j][x][y] >= t) { + return false; + } + } + return true; + } + + private boolean checkPass(int i, int x, int y, int t) { + for (int j = 0; j < i; j++) { + if (dist[j][x][y] == t) { + return false; + } + if (end[j][0] == x && end[j][1] == y && end[j][2] <= t) { + return false; + } + } + return true; + } + + private boolean isValid(int x, int y) { + return x >= 1 && x < m && y >= 1 && y < m; + } + + private int[][] getDirs(String piece) { + char c = piece.charAt(0); + return switch (c) { + case 'r' -> rookDirs; + case 'b' -> bishopDirs; + default -> queenDirs; + }; + } +} diff --git a/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.py b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.py new file mode 100644 index 0000000000000..f7d4e49c08881 --- /dev/null +++ b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.py @@ -0,0 +1,60 @@ +rook_dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)] +bishop_dirs = [(1, 1), (1, -1), (-1, 1), (-1, -1)] +queue_dirs = rook_dirs + bishop_dirs + + +def get_dirs(piece: str) -> List[Tuple[int, int]]: + match piece[0]: + case "r": + return rook_dirs + case "b": + return bishop_dirs + case _: + return queue_dirs + + +class Solution: + def countCombinations(self, pieces: List[str], positions: List[List[int]]) -> int: + def check_stop(i: int, x: int, y: int, t: int) -> bool: + return all(dist[j][x][y] < t for j in range(i)) + + def check_pass(i: int, x: int, y: int, t: int) -> bool: + for j in range(i): + if dist[j][x][y] == t: + return False + if end[j][0] == x and end[j][1] == y and end[j][2] <= t: + return False + return True + + def dfs(i: int) -> None: + if i >= n: + nonlocal ans + ans += 1 + return + x, y = positions[i] + dist[i][:] = [[-1] * m for _ in range(m)] + dist[i][x][y] = 0 + end[i] = (x, y, 0) + if check_stop(i, x, y, 0): + dfs(i + 1) + dirs = get_dirs(pieces[i]) + for dx, dy in dirs: + dist[i][:] = [[-1] * m for _ in range(m)] + dist[i][x][y] = 0 + nx, ny, nt = x + dx, y + dy, 1 + while 1 <= nx < m and 1 <= ny < m and check_pass(i, nx, ny, nt): + dist[i][nx][ny] = nt + end[i] = (nx, ny, nt) + if check_stop(i, nx, ny, nt): + dfs(i + 1) + nx += dx + ny += dy + nt += 1 + + n = len(pieces) + m = 9 + dist = [[[-1] * m for _ in range(m)] for _ in range(n)] + end = [(0, 0, 0) for _ in range(n)] + ans = 0 + dfs(0) + return ans diff --git a/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.ts b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.ts new file mode 100644 index 0000000000000..629c4a5aa7a5d --- /dev/null +++ b/solution/2000-2099/2056.Number of Valid Move Combinations On Chessboard/Solution.ts @@ -0,0 +1,108 @@ +const rookDirs: [number, number][] = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], +]; +const bishopDirs: [number, number][] = [ + [1, 1], + [1, -1], + [-1, 1], + [-1, -1], +]; +const queenDirs = [...rookDirs, ...bishopDirs]; + +function countCombinations(pieces: string[], positions: number[][]): number { + const n = pieces.length; + const m = 9; + let ans = 0; + + const dist = Array.from({ length: n }, () => + Array.from({ length: m }, () => Array(m).fill(-1)), + ); + + const end: [number, number, number][] = Array(n).fill([0, 0, 0]); + + const resetDist = (i: number) => { + for (let j = 0; j < m; j++) { + for (let k = 0; k < m; k++) { + dist[i][j][k] = -1; + } + } + }; + + const checkStop = (i: number, x: number, y: number, t: number): boolean => { + for (let j = 0; j < i; j++) { + if (dist[j][x][y] >= t) { + return false; + } + } + return true; + }; + + const checkPass = (i: number, x: number, y: number, t: number): boolean => { + for (let j = 0; j < i; j++) { + if (dist[j][x][y] === t) { + return false; + } + if (end[j][0] === x && end[j][1] === y && end[j][2] <= t) { + return false; + } + } + return true; + }; + + const isValid = (x: number, y: number): boolean => { + return x >= 1 && x < m && y >= 1 && y < m; + }; + + const getDirs = (piece: string): [number, number][] => { + switch (piece[0]) { + case 'r': + return rookDirs; + case 'b': + return bishopDirs; + default: + return queenDirs; + } + }; + + const dfs = (i: number) => { + if (i >= n) { + ans++; + return; + } + + const [x, y] = positions[i]; + resetDist(i); + dist[i][x][y] = 0; + end[i] = [x, y, 0]; + + if (checkStop(i, x, y, 0)) { + dfs(i + 1); + } + + const dirs = getDirs(pieces[i]); + for (const [dx, dy] of dirs) { + resetDist(i); + dist[i][x][y] = 0; + let nx = x + dx, + ny = y + dy, + nt = 1; + + while (isValid(nx, ny) && checkPass(i, nx, ny, nt)) { + dist[i][nx][ny] = nt; + end[i] = [nx, ny, nt]; + if (checkStop(i, nx, ny, nt)) { + dfs(i + 1); + } + nx += dx; + ny += dy; + nt++; + } + } + }; + + dfs(0); + return ans; +}