Skip to content

Commit 6548239

Browse files
authored
Improved task 3283
1 parent 487ab8a commit 6548239

File tree

2 files changed

+117
-71
lines changed
  • src
    • main/kotlin/g3201_3300/s3283_maximum_number_of_moves_to_kill_all_pawns
    • test/kotlin/g3201_3300/s3283_maximum_number_of_moves_to_kill_all_pawns

2 files changed

+117
-71
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,114 @@
11
package g3201_3300.s3283_maximum_number_of_moves_to_kill_all_pawns
22

33
// #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%)
55

6-
import java.util.LinkedList
7-
import java.util.Queue
86
import kotlin.math.max
97
import kotlin.math.min
108

119
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) {
1611
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
3316
}
34-
return minimax(n, (1 shl n) - 1, true)
17+
pos[kx][ky] = n
3518
}
3619

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+
}
5354
}
55+
steps++
5456
}
5557
}
56-
memo[lastPos]!![remainingPawns] = result
57-
return result
5858
}
5959

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+
}
8286
}
87+
dp[mask][i] = result
8388
}
8489
}
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)
87100
}
88101

89102
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),
92107
intArrayOf(-2, 1),
108+
intArrayOf(-2, -1),
93109
intArrayOf(-1, -2),
94-
intArrayOf(-1, 2),
95110
intArrayOf(1, -2),
96-
intArrayOf(1, 2),
97111
intArrayOf(2, -1),
98-
intArrayOf(2, 1),
99112
)
100113
}
101114
}

src/test/kotlin/g3201_3300/s3283_maximum_number_of_moves_to_kill_all_pawns/SolutionTest.kt

+33
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,37 @@ internal class SolutionTest {
3636
equalTo<Int>(3),
3737
)
3838
}
39+
40+
@Test
41+
fun maxMoves4() {
42+
assertThat(
43+
Solution().maxMoves(0, 0, arrayOf()),
44+
equalTo(0),
45+
)
46+
}
47+
48+
@Test
49+
fun maxMoves5() {
50+
assertThat(
51+
Solution().maxMoves(49, 49, arrayOf(intArrayOf(48, 48))),
52+
equalTo(4),
53+
)
54+
}
55+
56+
@Test
57+
fun maxMoves6() {
58+
assertThat(
59+
Solution().maxMoves(1, 1, arrayOf(intArrayOf(2, 2), intArrayOf(2, 2), intArrayOf(3, 3))),
60+
equalTo(6),
61+
)
62+
}
63+
64+
@Test
65+
fun maxMoves7() {
66+
val positions = Array(50) { intArrayOf(it, it) }
67+
assertThat(
68+
Solution().maxMoves(0, 0, positions),
69+
equalTo(266),
70+
)
71+
}
3972
}

0 commit comments

Comments
 (0)