|
59 | 59 |
|
60 | 60 | <!-- 这里可写通用的实现逻辑 -->
|
61 | 61 |
|
| 62 | +**方法一:朴素 BFS** |
| 63 | + |
| 64 | +题目实际上是求一个状态图中从初始状态到目标状态的最短路径,因此可以使用 BFS 求解。初始状态为 `grid`,目标状态为 `[[1, 1, 1], [1, 1, 1], [1, 1, 1]]`,在每次操作中,我们可以将一个单元格大于 $1$ 的石头移动到相邻的一个不超过 $1$ 的单元格。如果找到了目标状态,那么就可以返回当前的层数,即为最少移动次数。 |
| 65 | + |
| 66 | +**方法二:状态压缩动态规划** |
| 67 | + |
| 68 | +我们可以把所有值为 $0$ 的单元格坐标 $(i, j)$ 放入数组 $left$ 中,如果单元格的值 $v$ 大于 $1$,那么我们把 $v-1$ 个坐标 $(i, j)$ 放入数组 $right$ 中。那么问题就转化为,每个 $right$ 中的坐标 $(i, j)$ 都要移动到 $left$ 中的一个坐标 $(x, y)$,求最少的移动次数。 |
| 69 | + |
| 70 | +我们记 $left$ 的长度为 $n$,那么我们可以使用 $n$ 位二进制数来表示 $left$ 中的每个坐标是否被 $right$ 中的坐标填充,其中 $1$ 表示被填充,而 $0$ 表示未被填充。初始时 $f[i] = \infty$,其余 $f[0]=0$。 |
| 71 | + |
| 72 | +考虑 $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]$。 |
| 73 | + |
| 74 | +时间复杂度 $O(n \times 2^n)$,空间复杂度 $O(2^n)$。其中 $n$ 表示 $left$ 的长度,本题中 $n \le 9$。 |
| 75 | + |
62 | 76 | <!-- tabs:start -->
|
63 | 77 |
|
64 | 78 | ### **Python3**
|
@@ -93,6 +107,32 @@ class Solution:
|
93 | 107 | ans += 1
|
94 | 108 | ```
|
95 | 109 |
|
| 110 | +```python |
| 111 | +class Solution: |
| 112 | + def minimumMoves(self, grid: List[List[int]]) -> int: |
| 113 | + def cal(a: tuple, b: tuple) -> int: |
| 114 | + return abs(a[0] - b[0]) + abs(a[1] - b[1]) |
| 115 | + |
| 116 | + left, right = [], [] |
| 117 | + for i in range(3): |
| 118 | + for j in range(3): |
| 119 | + if grid[i][j] == 0: |
| 120 | + left.append((i, j)) |
| 121 | + else: |
| 122 | + for _ in range(grid[i][j] - 1): |
| 123 | + right.append((i, j)) |
| 124 | + |
| 125 | + n = len(left) |
| 126 | + f = [inf] * (1 << n) |
| 127 | + f[0] = 0 |
| 128 | + for i in range(1, 1 << n): |
| 129 | + k = i.bit_count() |
| 130 | + for j in range(n): |
| 131 | + if i >> j & 1: |
| 132 | + f[i] = min(f[i], f[i ^ (1 << j)] + cal(left[k - 1], right[j])) |
| 133 | + return f[-1] |
| 134 | +``` |
| 135 | + |
96 | 136 | ### **Java**
|
97 | 137 |
|
98 | 138 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
@@ -163,22 +203,170 @@ class Solution {
|
163 | 203 | }
|
164 | 204 | ```
|
165 | 205 |
|
| 206 | +```java |
| 207 | +class Solution { |
| 208 | + public int minimumMoves(int[][] grid) { |
| 209 | + List<int[]> left = new ArrayList<>(); |
| 210 | + List<int[]> right = new ArrayList<>(); |
| 211 | + for (int i = 0; i < 3; ++i) { |
| 212 | + for (int j = 0; j < 3; ++j) { |
| 213 | + if (grid[i][j] == 0) { |
| 214 | + left.add(new int[] {i, j}); |
| 215 | + } else { |
| 216 | + for (int k = 1; k < grid[i][j]; ++k) { |
| 217 | + right.add(new int[] {i, j}); |
| 218 | + } |
| 219 | + } |
| 220 | + } |
| 221 | + } |
| 222 | + int n = left.size(); |
| 223 | + int[] f = new int[1 << n]; |
| 224 | + Arrays.fill(f, 1 << 30); |
| 225 | + f[0] = 0; |
| 226 | + for (int i = 1; i < 1 << n; ++i) { |
| 227 | + int k = Integer.bitCount(i); |
| 228 | + for (int j = 0; j < n; ++j) { |
| 229 | + if ((i >> j & 1) == 1) { |
| 230 | + f[i] = Math.min(f[i], f[i ^ (1 << j)] + cal(left.get(k - 1), right.get(j))); |
| 231 | + } |
| 232 | + } |
| 233 | + } |
| 234 | + return f[(1 << n) - 1]; |
| 235 | + } |
| 236 | + |
| 237 | + private int cal(int[] a, int[] b) { |
| 238 | + return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]); |
| 239 | + } |
| 240 | +} |
| 241 | +``` |
| 242 | + |
166 | 243 | ### **C++**
|
167 | 244 |
|
168 | 245 | ```cpp
|
169 |
| - |
| 246 | +class Solution { |
| 247 | +public: |
| 248 | + int minimumMoves(vector<vector<int>>& grid) { |
| 249 | + using pii = pair<int, int>; |
| 250 | + vector<pii> left, right; |
| 251 | + for (int i = 0; i < 3; ++i) { |
| 252 | + for (int j = 0; j < 3; ++j) { |
| 253 | + if (grid[i][j] == 0) { |
| 254 | + left.emplace_back(i, j); |
| 255 | + } else { |
| 256 | + for (int k = 1; k < grid[i][j]; ++k) { |
| 257 | + right.emplace_back(i, j); |
| 258 | + } |
| 259 | + } |
| 260 | + } |
| 261 | + } |
| 262 | + auto cal = [](pii a, pii b) { |
| 263 | + return abs(a.first - b.first) + abs(a.second - b.second); |
| 264 | + }; |
| 265 | + int n = left.size(); |
| 266 | + int f[1 << n]; |
| 267 | + memset(f, 0x3f, sizeof(f)); |
| 268 | + f[0] = 0; |
| 269 | + for (int i = 1; i < 1 << n; ++i) { |
| 270 | + int k = __builtin_popcount(i); |
| 271 | + for (int j = 0; j < n; ++j) { |
| 272 | + if (i >> j & 1) { |
| 273 | + f[i] = min(f[i], f[i ^ (1 << j)] + cal(left[k - 1], right[j])); |
| 274 | + } |
| 275 | + } |
| 276 | + } |
| 277 | + return f[(1 << n) - 1]; |
| 278 | + } |
| 279 | +}; |
170 | 280 | ```
|
171 | 281 |
|
172 | 282 | ### **Go**
|
173 | 283 |
|
174 | 284 | ```go
|
| 285 | +func minimumMoves(grid [][]int) int { |
| 286 | + left := [][2]int{} |
| 287 | + right := [][2]int{} |
| 288 | + for i := 0; i < 3; i++ { |
| 289 | + for j := 0; j < 3; j++ { |
| 290 | + if grid[i][j] == 0 { |
| 291 | + left = append(left, [2]int{i, j}) |
| 292 | + } else { |
| 293 | + for k := 1; k < grid[i][j]; k++ { |
| 294 | + right = append(right, [2]int{i, j}) |
| 295 | + } |
| 296 | + } |
| 297 | + } |
| 298 | + } |
| 299 | + cal := func(a, b [2]int) int { |
| 300 | + return abs(a[0]-b[0]) + abs(a[1]-b[1]) |
| 301 | + } |
| 302 | + n := len(left) |
| 303 | + f := make([]int, 1<<n) |
| 304 | + f[0] = 0 |
| 305 | + for i := 1; i < 1<<n; i++ { |
| 306 | + f[i] = 1 << 30 |
| 307 | + k := bits.OnesCount(uint(i)) |
| 308 | + for j := 0; j < n; j++ { |
| 309 | + if i>>j&1 == 1 { |
| 310 | + f[i] = min(f[i], f[i^(1<<j)]+cal(left[k-1], right[j])) |
| 311 | + } |
| 312 | + } |
| 313 | + } |
| 314 | + return f[(1<<n)-1] |
| 315 | +} |
175 | 316 |
|
| 317 | +func min(a, b int) int { |
| 318 | + if a < b { |
| 319 | + return a |
| 320 | + } |
| 321 | + return b |
| 322 | +} |
| 323 | +
|
| 324 | +func abs(x int) int { |
| 325 | + if x < 0 { |
| 326 | + return -x |
| 327 | + } |
| 328 | + return x |
| 329 | +} |
176 | 330 | ```
|
177 | 331 |
|
178 | 332 | ### **TypeScript**
|
179 | 333 |
|
180 | 334 | ```ts
|
181 |
| - |
| 335 | +function minimumMoves(grid: number[][]): number { |
| 336 | + const left: number[][] = []; |
| 337 | + const right: number[][] = []; |
| 338 | + for (let i = 0; i < 3; ++i) { |
| 339 | + for (let j = 0; j < 3; ++j) { |
| 340 | + if (grid[i][j] === 0) { |
| 341 | + left.push([i, j]); |
| 342 | + } else { |
| 343 | + for (let k = 1; k < grid[i][j]; ++k) { |
| 344 | + right.push([i, j]); |
| 345 | + } |
| 346 | + } |
| 347 | + } |
| 348 | + } |
| 349 | + const cal = (a: number[], b: number[]) => { |
| 350 | + return Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]); |
| 351 | + }; |
| 352 | + const n = left.length; |
| 353 | + const f: number[] = Array(1 << n).fill(1 << 30); |
| 354 | + f[0] = 0; |
| 355 | + for (let i = 0; i < 1 << n; ++i) { |
| 356 | + let k = 0; |
| 357 | + for (let j = 0; j < n; ++j) { |
| 358 | + if ((i >> j) & 1) { |
| 359 | + ++k; |
| 360 | + } |
| 361 | + } |
| 362 | + for (let j = 0; j < n; ++j) { |
| 363 | + if ((i >> j) & 1) { |
| 364 | + f[i] = Math.min(f[i], f[i ^ (1 << j)] + cal(left[k - 1], right[j])); |
| 365 | + } |
| 366 | + } |
| 367 | + } |
| 368 | + return f[(1 << n) - 1]; |
| 369 | +} |
182 | 370 | ```
|
183 | 371 |
|
184 | 372 | ### **...**
|
|
0 commit comments