|
1 | 1 | package g3201_3300.s3283_maximum_number_of_moves_to_kill_all_pawns
|
2 | 2 |
|
3 | 3 | // #Hard #Array #Math #Breadth_First_Search #Bit_Manipulation #Bitmask #Game_Theory
|
4 |
| -// #2024_09_11_Time_638_ms_(100.00%)_Space_62.2_MB_(87.50%) |
| 4 | +// #2025_03_22_Time_147_ms_(100.00%)_Space_67.70_MB_(100.00%) |
5 | 5 |
|
6 |
| -import java.util.LinkedList |
7 |
| -import java.util.Queue |
8 | 6 | import kotlin.math.max
|
9 | 7 | import kotlin.math.min
|
10 | 8 |
|
11 | 9 | class Solution {
|
12 |
| - private lateinit var distances: Array<IntArray> |
13 |
| - private lateinit var memo: Array<Array<Int?>?> |
14 |
| - |
15 |
| - fun maxMoves(kx: Int, ky: Int, positions: Array<IntArray>): Int { |
| 10 | + private fun initializePositions(positions: Array<IntArray>, pos: Array<IntArray>, kx: Int, ky: Int) { |
16 | 11 | val n = positions.size
|
17 |
| - distances = Array<IntArray>(n + 1) { IntArray(n + 1) { 0 } } |
18 |
| - memo = Array<Array<Int?>?>(n + 1) { arrayOfNulls<Int>(1 shl n) } |
19 |
| - // Calculate distances between all pairs of positions (including knight's initial position) |
20 |
| - for (i in 0 until n) { |
21 |
| - distances[n][i] = calculateMoves(kx, ky, positions[i][0], positions[i][1]) |
22 |
| - for (j in i + 1 until n) { |
23 |
| - val dist = |
24 |
| - calculateMoves( |
25 |
| - positions[i][0], |
26 |
| - positions[i][1], |
27 |
| - positions[j][0], |
28 |
| - positions[j][1], |
29 |
| - ) |
30 |
| - distances[j][i] = dist |
31 |
| - distances[i][j] = distances[j][i] |
32 |
| - } |
| 12 | + for (i in 0..<n) { |
| 13 | + val x = positions[i][0] |
| 14 | + val y = positions[i][1] |
| 15 | + pos[x][y] = i |
33 | 16 | }
|
34 |
| - return minimax(n, (1 shl n) - 1, true) |
| 17 | + pos[kx][ky] = n |
35 | 18 | }
|
36 | 19 |
|
37 |
| - private fun minimax(lastPos: Int, remainingPawns: Int, isAlice: Boolean): Int { |
38 |
| - if (remainingPawns == 0) { |
39 |
| - return 0 |
40 |
| - } |
41 |
| - if (memo[lastPos]!![remainingPawns] != null) { |
42 |
| - return memo[lastPos]!![remainingPawns]!! |
43 |
| - } |
44 |
| - var result = if (isAlice) 0 else Int.Companion.MAX_VALUE |
45 |
| - for (i in 0 until distances.size - 1) { |
46 |
| - if ((remainingPawns and (1 shl i)) != 0) { |
47 |
| - val newRemainingPawns = remainingPawns and (1 shl i).inv() |
48 |
| - val moveValue = distances[lastPos][i] + minimax(i, newRemainingPawns, !isAlice) |
49 |
| - result = if (isAlice) { |
50 |
| - max(result, moveValue) |
51 |
| - } else { |
52 |
| - min(result, moveValue) |
| 20 | + private fun calculateDistances(positions: Array<IntArray>, pos: Array<IntArray>, distances: Array<IntArray>) { |
| 21 | + val n = positions.size |
| 22 | + for (i in 0..<n) { |
| 23 | + var count = n - i |
| 24 | + val visited = Array<BooleanArray>(50) { BooleanArray(50) } |
| 25 | + visited[positions[i][0]][positions[i][1]] = true |
| 26 | + val que: ArrayDeque<IntArray> = ArrayDeque() |
| 27 | + que.add(intArrayOf(positions[i][0], positions[i][1])) |
| 28 | + var steps = 1 |
| 29 | + while (que.isNotEmpty() && count > 0) { |
| 30 | + var size = que.size |
| 31 | + while (size-- > 0) { |
| 32 | + val cur = que.removeFirst() |
| 33 | + val x = cur[0] |
| 34 | + val y = cur[1] |
| 35 | + for (d in DIRECTIONS) { |
| 36 | + val nx = x + d[0] |
| 37 | + val ny = y + d[1] |
| 38 | + if (0 <= nx && nx < 50 && 0 <= ny && ny < 50 && !visited[nx][ny]) { |
| 39 | + que.add(intArrayOf(nx, ny)) |
| 40 | + visited[nx][ny] = true |
| 41 | + val j = pos[nx][ny] |
| 42 | + if (j > i) { |
| 43 | + distances[j][i] = steps |
| 44 | + distances[i][j] = distances[j][i] |
| 45 | + if (--count == 0) { |
| 46 | + break |
| 47 | + } |
| 48 | + } |
| 49 | + } |
| 50 | + } |
| 51 | + if (count == 0) { |
| 52 | + break |
| 53 | + } |
53 | 54 | }
|
| 55 | + steps++ |
54 | 56 | }
|
55 | 57 | }
|
56 |
| - memo[lastPos]!![remainingPawns] = result |
57 |
| - return result |
58 | 58 | }
|
59 | 59 |
|
60 |
| - private fun calculateMoves(x1: Int, y1: Int, x2: Int, y2: Int): Int { |
61 |
| - if (x1 == x2 && y1 == y2) { |
62 |
| - return 0 |
63 |
| - } |
64 |
| - val visited = Array<BooleanArray>(50) { BooleanArray(50) } |
65 |
| - val queue: Queue<IntArray> = LinkedList<IntArray>() |
66 |
| - queue.offer(intArrayOf(x1, y1, 0)) |
67 |
| - visited[x1][y1] = true |
68 |
| - while (queue.isNotEmpty()) { |
69 |
| - val current = queue.poll() |
70 |
| - val x = current[0] |
71 |
| - val y = current[1] |
72 |
| - val moves = current[2] |
73 |
| - for (move in KNIGHT_MOVES) { |
74 |
| - val nx = x + move[0] |
75 |
| - val ny = y + move[1] |
76 |
| - if (nx == x2 && ny == y2) { |
77 |
| - return moves + 1 |
78 |
| - } |
79 |
| - if (nx >= 0 && nx < 50 && ny >= 0 && ny < 50 && !visited[nx][ny]) { |
80 |
| - queue.offer(intArrayOf(nx, ny, moves + 1)) |
81 |
| - visited[nx][ny] = true |
| 60 | + private fun calculateDP(n: Int, distances: Array<IntArray>): Int { |
| 61 | + val m = (1 shl n) - 1 |
| 62 | + val dp = Array<IntArray>(1 shl n) { IntArray(n + 1) } |
| 63 | + for (mask in 1..<(1 shl n)) { |
| 64 | + val isEven = (Integer.bitCount(m xor mask)) % 2 == 0 |
| 65 | + for (i in 0..n) { |
| 66 | + var result = 0 |
| 67 | + if (isEven) { |
| 68 | + for (j in 0..<n) { |
| 69 | + if ((mask and (1 shl j)) > 0) { |
| 70 | + result = max( |
| 71 | + result, |
| 72 | + dp[mask xor (1 shl j)][j] + distances[i][j], |
| 73 | + ) |
| 74 | + } |
| 75 | + } |
| 76 | + } else { |
| 77 | + result = Int.Companion.MAX_VALUE |
| 78 | + for (j in 0..<n) { |
| 79 | + if ((mask and (1 shl j)) > 0) { |
| 80 | + result = min( |
| 81 | + result, |
| 82 | + dp[mask xor (1 shl j)][j] + distances[i][j], |
| 83 | + ) |
| 84 | + } |
| 85 | + } |
82 | 86 | }
|
| 87 | + dp[mask][i] = result |
83 | 88 | }
|
84 | 89 | }
|
85 |
| - // Should never reach here if input is valid |
86 |
| - return -1 |
| 90 | + return dp[m][n] |
| 91 | + } |
| 92 | + |
| 93 | + fun maxMoves(kx: Int, ky: Int, positions: Array<IntArray>): Int { |
| 94 | + val n = positions.size |
| 95 | + val pos = Array<IntArray>(50) { IntArray(50) } |
| 96 | + initializePositions(positions, pos, kx, ky) |
| 97 | + val distances = Array<IntArray>(n + 1) { IntArray(n + 1) } |
| 98 | + calculateDistances(positions, pos, distances) |
| 99 | + return calculateDP(n, distances) |
87 | 100 | }
|
88 | 101 |
|
89 | 102 | companion object {
|
90 |
| - private val KNIGHT_MOVES = arrayOf<IntArray>( |
91 |
| - intArrayOf(-2, -1), |
| 103 | + private val DIRECTIONS = arrayOf<IntArray>( |
| 104 | + intArrayOf(2, 1), |
| 105 | + intArrayOf(1, 2), |
| 106 | + intArrayOf(-1, 2), |
92 | 107 | intArrayOf(-2, 1),
|
| 108 | + intArrayOf(-2, -1), |
93 | 109 | intArrayOf(-1, -2),
|
94 |
| - intArrayOf(-1, 2), |
95 | 110 | intArrayOf(1, -2),
|
96 |
| - intArrayOf(1, 2), |
97 | 111 | intArrayOf(2, -1),
|
98 |
| - intArrayOf(2, 1), |
99 | 112 | )
|
100 | 113 | }
|
101 | 114 | }
|
0 commit comments