|
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_119_ms_(100.00%)_Space_66.82_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: java.util.Queue<IntArray> = java.util.ArrayDeque<IntArray>() |
| 27 | + que.offer(intArrayOf(positions[i][0], positions[i][1])) |
| 28 | + var steps = 1 |
| 29 | + while (!que.isEmpty() && count > 0) { |
| 30 | + var size = que.size |
| 31 | + while (size-- > 0) { |
| 32 | + val cur = que.poll() |
| 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.offer(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