diff --git a/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/README.md b/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/README.md index 0ee00e17913b1..bb710b3dd4277 100644 --- a/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/README.md +++ b/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/README.md @@ -180,6 +180,91 @@ class Solution { } ``` + + + + + + +### 方法二:状态压缩动态规划 + +我们可以把所有值为 $0$ 的单元格坐标 $(i, j)$ 放入数组 $left$ 中,如果单元格的值 $v$ 大于 $1$,那么我们把 $v-1$ 个坐标 $(i, j)$ 放入数组 $right$ 中。那么问题就转化为,每个 $right$ 中的坐标 $(i, j)$ 都要移动到 $left$ 中的一个坐标 $(x, y)$,求最少的移动次数。 + +我们记 $left$ 的长度为 $n$,那么我们可以使用 $n$ 位二进制数来表示 $left$ 中的每个坐标是否被 $right$ 中的坐标填充,其中 $1$ 表示被填充,而 $0$ 表示未被填充。初始时 $f[i] = \infty$,其余 $f[0]=0$。 + +考虑 $f[i]$,记当前 $i$ 的二进制表示中 $1$ 的个数为 $k$,我们在 $[0..n)$ 的范围内枚举 $j$,如果 $i$ 的第 $j$ 位为 $1$,那么 $f[i]$ 可以由 $f[i \oplus (1 << j)]$ 转移而来,转移的代价为 $cal(left[k-1], right[j])$,其中 $cal$ 表示两个坐标之间的曼哈顿距离。最终答案为 $f[(1 << n) - 1]$。 + +时间复杂度 $O(n \times 2^n)$,空间复杂度 $O(2^n)$。其中 $n$ 表示 $left$ 的长度,本题中 $n \le 9$。 + + + +#### Python3 + +```python +class Solution: + def minimumMoves(self, grid: List[List[int]]) -> int: + def cal(a: tuple, b: tuple) -> int: + return abs(a[0] - b[0]) + abs(a[1] - b[1]) + + left, right = [], [] + for i in range(3): + for j in range(3): + if grid[i][j] == 0: + left.append((i, j)) + else: + for _ in range(grid[i][j] - 1): + right.append((i, j)) + + n = len(left) + f = [inf] * (1 << n) + f[0] = 0 + for i in range(1, 1 << n): + k = i.bit_count() + for j in range(n): + if i >> j & 1: + f[i] = min(f[i], f[i ^ (1 << j)] + cal(left[k - 1], right[j])) + return f[-1] +``` + +#### Java + +```java +class Solution { + public int minimumMoves(int[][] grid) { + List left = new ArrayList<>(); + List right = new ArrayList<>(); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + if (grid[i][j] == 0) { + left.add(new int[] {i, j}); + } else { + for (int k = 1; k < grid[i][j]; ++k) { + right.add(new int[] {i, j}); + } + } + } + } + int n = left.size(); + int[] f = new int[1 << n]; + Arrays.fill(f, 1 << 30); + f[0] = 0; + for (int i = 1; i < 1 << n; ++i) { + int k = Integer.bitCount(i); + for (int j = 0; j < n; ++j) { + if ((i >> j & 1) == 1) { + f[i] = Math.min(f[i], f[i ^ (1 << j)] + cal(left.get(k - 1), right.get(j))); + } + } + } + return f[(1 << n) - 1]; + } + + private int cal(int[] a, int[] b) { + return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]); + } +} +``` + #### C++ ```cpp @@ -306,89 +391,4 @@ function minimumMoves(grid: number[][]): number { - - -### 方法二:状态压缩动态规划 - -我们可以把所有值为 $0$ 的单元格坐标 $(i, j)$ 放入数组 $left$ 中,如果单元格的值 $v$ 大于 $1$,那么我们把 $v-1$ 个坐标 $(i, j)$ 放入数组 $right$ 中。那么问题就转化为,每个 $right$ 中的坐标 $(i, j)$ 都要移动到 $left$ 中的一个坐标 $(x, y)$,求最少的移动次数。 - -我们记 $left$ 的长度为 $n$,那么我们可以使用 $n$ 位二进制数来表示 $left$ 中的每个坐标是否被 $right$ 中的坐标填充,其中 $1$ 表示被填充,而 $0$ 表示未被填充。初始时 $f[i] = \infty$,其余 $f[0]=0$。 - -考虑 $f[i]$,记当前 $i$ 的二进制表示中 $1$ 的个数为 $k$,我们在 $[0..n)$ 的范围内枚举 $j$,如果 $i$ 的第 $j$ 位为 $1$,那么 $f[i]$ 可以由 $f[i \oplus (1 << j)]$ 转移而来,转移的代价为 $cal(left[k-1], right[j])$,其中 $cal$ 表示两个坐标之间的曼哈顿距离。最终答案为 $f[(1 << n) - 1]$。 - -时间复杂度 $O(n \times 2^n)$,空间复杂度 $O(2^n)$。其中 $n$ 表示 $left$ 的长度,本题中 $n \le 9$。 - - - -#### Python3 - -```python -class Solution: - def minimumMoves(self, grid: List[List[int]]) -> int: - def cal(a: tuple, b: tuple) -> int: - return abs(a[0] - b[0]) + abs(a[1] - b[1]) - - left, right = [], [] - for i in range(3): - for j in range(3): - if grid[i][j] == 0: - left.append((i, j)) - else: - for _ in range(grid[i][j] - 1): - right.append((i, j)) - - n = len(left) - f = [inf] * (1 << n) - f[0] = 0 - for i in range(1, 1 << n): - k = i.bit_count() - for j in range(n): - if i >> j & 1: - f[i] = min(f[i], f[i ^ (1 << j)] + cal(left[k - 1], right[j])) - return f[-1] -``` - -#### Java - -```java -class Solution { - public int minimumMoves(int[][] grid) { - List left = new ArrayList<>(); - List right = new ArrayList<>(); - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - if (grid[i][j] == 0) { - left.add(new int[] {i, j}); - } else { - for (int k = 1; k < grid[i][j]; ++k) { - right.add(new int[] {i, j}); - } - } - } - } - int n = left.size(); - int[] f = new int[1 << n]; - Arrays.fill(f, 1 << 30); - f[0] = 0; - for (int i = 1; i < 1 << n; ++i) { - int k = Integer.bitCount(i); - for (int j = 0; j < n; ++j) { - if ((i >> j & 1) == 1) { - f[i] = Math.min(f[i], f[i ^ (1 << j)] + cal(left.get(k - 1), right.get(j))); - } - } - } - return f[(1 << n) - 1]; - } - - private int cal(int[] a, int[] b) { - return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]); - } -} -``` - - - - - diff --git a/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/README_EN.md b/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/README_EN.md index ed438d555fb94..5d21c53790925 100644 --- a/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/README_EN.md +++ b/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/README_EN.md @@ -174,6 +174,91 @@ class Solution { } ``` + + + + + + +### Solution 2: State Compression Dynamic Programming + +We can put all the coordinates $(i, j)$ of cells with a value of $0$ into an array $left$. If the value $v$ of a cell is greater than $1$, we put $v-1$ coordinates $(i, j)$ into an array $right$. The problem then becomes that each coordinate $(i, j)$ in $right$ needs to be moved to a coordinate $(x, y)$ in $left$, and we need to find the minimum number of moves. + +Let's denote the length of $left$ as $n$. We can use an $n$-bit binary number to represent whether each coordinate in $left$ is filled by a coordinate in $right$, where $1$ represents being filled, and $0$ represents not being filled. Initially, $f[i] = \infty$, and the rest $f[0]=0$. + +Consider $f[i]$, let the number of $1$s in the binary representation of $i$ be $k$. We enumerate $j$ in the range $[0..n)$, if the $j$th bit of $i$ is $1$, then $f[i]$ can be transferred from $f[i \oplus (1 << j)]$, and the cost of the transfer is $cal(left[k-1], right[j])$, where $cal$ represents the Manhattan distance between two coordinates. The final answer is $f[(1 << n) - 1]$. + +The time complexity is $O(n \times 2^n)$, and the space complexity is $O(2^n)$. Here, $n$ is the length of $left$, and in this problem, $n \le 9$. + + + +#### Python3 + +```python +class Solution: + def minimumMoves(self, grid: List[List[int]]) -> int: + def cal(a: tuple, b: tuple) -> int: + return abs(a[0] - b[0]) + abs(a[1] - b[1]) + + left, right = [], [] + for i in range(3): + for j in range(3): + if grid[i][j] == 0: + left.append((i, j)) + else: + for _ in range(grid[i][j] - 1): + right.append((i, j)) + + n = len(left) + f = [inf] * (1 << n) + f[0] = 0 + for i in range(1, 1 << n): + k = i.bit_count() + for j in range(n): + if i >> j & 1: + f[i] = min(f[i], f[i ^ (1 << j)] + cal(left[k - 1], right[j])) + return f[-1] +``` + +#### Java + +```java +class Solution { + public int minimumMoves(int[][] grid) { + List left = new ArrayList<>(); + List right = new ArrayList<>(); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + if (grid[i][j] == 0) { + left.add(new int[] {i, j}); + } else { + for (int k = 1; k < grid[i][j]; ++k) { + right.add(new int[] {i, j}); + } + } + } + } + int n = left.size(); + int[] f = new int[1 << n]; + Arrays.fill(f, 1 << 30); + f[0] = 0; + for (int i = 1; i < 1 << n; ++i) { + int k = Integer.bitCount(i); + for (int j = 0; j < n; ++j) { + if ((i >> j & 1) == 1) { + f[i] = Math.min(f[i], f[i ^ (1 << j)] + cal(left.get(k - 1), right.get(j))); + } + } + } + return f[(1 << n) - 1]; + } + + private int cal(int[] a, int[] b) { + return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]); + } +} +``` + #### C++ ```cpp @@ -300,89 +385,4 @@ function minimumMoves(grid: number[][]): number { - - -### Solution 2: State Compression Dynamic Programming - -We can put all the coordinates $(i, j)$ of cells with a value of $0$ into an array $left$. If the value $v$ of a cell is greater than $1$, we put $v-1$ coordinates $(i, j)$ into an array $right$. The problem then becomes that each coordinate $(i, j)$ in $right$ needs to be moved to a coordinate $(x, y)$ in $left$, and we need to find the minimum number of moves. - -Let's denote the length of $left$ as $n$. We can use an $n$-bit binary number to represent whether each coordinate in $left$ is filled by a coordinate in $right$, where $1$ represents being filled, and $0$ represents not being filled. Initially, $f[i] = \infty$, and the rest $f[0]=0$. - -Consider $f[i]$, let the number of $1$s in the binary representation of $i$ be $k$. We enumerate $j$ in the range $[0..n)$, if the $j$th bit of $i$ is $1$, then $f[i]$ can be transferred from $f[i \oplus (1 << j)]$, and the cost of the transfer is $cal(left[k-1], right[j])$, where $cal$ represents the Manhattan distance between two coordinates. The final answer is $f[(1 << n) - 1]$. - -The time complexity is $O(n \times 2^n)$, and the space complexity is $O(2^n)$. Here, $n$ is the length of $left$, and in this problem, $n \le 9$. - - - -#### Python3 - -```python -class Solution: - def minimumMoves(self, grid: List[List[int]]) -> int: - def cal(a: tuple, b: tuple) -> int: - return abs(a[0] - b[0]) + abs(a[1] - b[1]) - - left, right = [], [] - for i in range(3): - for j in range(3): - if grid[i][j] == 0: - left.append((i, j)) - else: - for _ in range(grid[i][j] - 1): - right.append((i, j)) - - n = len(left) - f = [inf] * (1 << n) - f[0] = 0 - for i in range(1, 1 << n): - k = i.bit_count() - for j in range(n): - if i >> j & 1: - f[i] = min(f[i], f[i ^ (1 << j)] + cal(left[k - 1], right[j])) - return f[-1] -``` - -#### Java - -```java -class Solution { - public int minimumMoves(int[][] grid) { - List left = new ArrayList<>(); - List right = new ArrayList<>(); - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - if (grid[i][j] == 0) { - left.add(new int[] {i, j}); - } else { - for (int k = 1; k < grid[i][j]; ++k) { - right.add(new int[] {i, j}); - } - } - } - } - int n = left.size(); - int[] f = new int[1 << n]; - Arrays.fill(f, 1 << 30); - f[0] = 0; - for (int i = 1; i < 1 << n; ++i) { - int k = Integer.bitCount(i); - for (int j = 0; j < n; ++j) { - if ((i >> j & 1) == 1) { - f[i] = Math.min(f[i], f[i ^ (1 << j)] + cal(left.get(k - 1), right.get(j))); - } - } - } - return f[(1 << n) - 1]; - } - - private int cal(int[] a, int[] b) { - return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]); - } -} -``` - - - - - diff --git a/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/Solution.cpp b/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/Solution2.cpp similarity index 100% rename from solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/Solution.cpp rename to solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/Solution2.cpp diff --git a/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/Solution.go b/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/Solution2.go similarity index 100% rename from solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/Solution.go rename to solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/Solution2.go diff --git a/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/Solution.ts b/solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/Solution2.ts similarity index 100% rename from solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/Solution.ts rename to solution/2800-2899/2850.Minimum Moves to Spread Stones Over Grid/Solution2.ts