|
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_09_Time_250_ms_(98.43%)_Space_50.1_MB_(66.27%) |
| 4 | +// #2025_03_22_Time_126_ms_(100.00%)_Space_48.23_MB_(72.09%) |
5 | 5 |
|
6 | | -import java.util.LinkedList; |
| 6 | +import java.util.ArrayDeque; |
7 | 7 | import java.util.Queue; |
8 | 8 |
|
9 | 9 | public class Solution { |
10 | | - private static final int[][] KNIGHT_MOVES = { |
11 | | - {-2, -1}, {-2, 1}, {-1, -2}, {-1, 2}, |
12 | | - {1, -2}, {1, 2}, {2, -1}, {2, 1} |
| 10 | + private static final int[][] DIRECTIONS = { |
| 11 | + {2, 1}, {1, 2}, {-1, 2}, {-2, 1}, {-2, -1}, {-1, -2}, {1, -2}, {2, -1} |
13 | 12 | }; |
14 | | - private int[][] distances; |
15 | | - private Integer[][] memo; |
16 | 13 |
|
17 | | - public int maxMoves(int kx, int ky, int[][] positions) { |
| 14 | + private void initializePositions(int[][] positions, int[][] pos, int kx, int ky) { |
18 | 15 | int n = positions.length; |
19 | | - distances = new int[n + 1][n + 1]; |
20 | | - memo = new Integer[n + 1][1 << n]; |
21 | | - // Calculate distances between all pairs of positions (including knight's initial position) |
22 | 16 | for (int i = 0; i < n; i++) { |
23 | | - distances[n][i] = calculateMoves(kx, ky, positions[i][0], positions[i][1]); |
24 | | - for (int j = i + 1; j < n; j++) { |
25 | | - int dist = |
26 | | - calculateMoves( |
27 | | - positions[i][0], positions[i][1], positions[j][0], positions[j][1]); |
28 | | - distances[i][j] = distances[j][i] = dist; |
29 | | - } |
| 17 | + int x = positions[i][0]; |
| 18 | + int y = positions[i][1]; |
| 19 | + pos[x][y] = i; |
30 | 20 | } |
31 | | - return minimax(n, (1 << n) - 1, true); |
| 21 | + pos[kx][ky] = n; |
32 | 22 | } |
33 | 23 |
|
34 | | - private int minimax(int lastPos, int remainingPawns, boolean isAlice) { |
35 | | - if (remainingPawns == 0) { |
36 | | - return 0; |
37 | | - } |
38 | | - if (memo[lastPos][remainingPawns] != null) { |
39 | | - return memo[lastPos][remainingPawns]; |
40 | | - } |
41 | | - int result = isAlice ? 0 : Integer.MAX_VALUE; |
42 | | - for (int i = 0; i < distances.length - 1; i++) { |
43 | | - if ((remainingPawns & (1 << i)) != 0) { |
44 | | - int newRemainingPawns = remainingPawns & ~(1 << i); |
45 | | - int moveValue = distances[lastPos][i] + minimax(i, newRemainingPawns, !isAlice); |
46 | | - |
47 | | - if (isAlice) { |
48 | | - result = Math.max(result, moveValue); |
49 | | - } else { |
50 | | - result = Math.min(result, moveValue); |
| 24 | + private void calculateDistances(int[][] positions, int[][] pos, int[][] distances) { |
| 25 | + int n = positions.length; |
| 26 | + for (int i = 0; i < n; i++) { |
| 27 | + int count = n - i; |
| 28 | + boolean[][] visited = new boolean[50][50]; |
| 29 | + visited[positions[i][0]][positions[i][1]] = true; |
| 30 | + Queue<int[]> que = new ArrayDeque<>(); |
| 31 | + que.offer(new int[] {positions[i][0], positions[i][1]}); |
| 32 | + int steps = 1; |
| 33 | + while (!que.isEmpty() && count > 0) { |
| 34 | + int size = que.size(); |
| 35 | + while (size-- > 0) { |
| 36 | + int[] cur = que.poll(); |
| 37 | + int x = cur[0]; |
| 38 | + int y = cur[1]; |
| 39 | + for (int[] d : DIRECTIONS) { |
| 40 | + int nx = x + d[0]; |
| 41 | + int ny = y + d[1]; |
| 42 | + if (0 <= nx && nx < 50 && 0 <= ny && ny < 50 && !visited[nx][ny]) { |
| 43 | + que.offer(new int[] {nx, ny}); |
| 44 | + visited[nx][ny] = true; |
| 45 | + int j = pos[nx][ny]; |
| 46 | + if (j > i) { |
| 47 | + distances[i][j] = distances[j][i] = steps; |
| 48 | + if (--count == 0) { |
| 49 | + break; |
| 50 | + } |
| 51 | + } |
| 52 | + } |
| 53 | + } |
| 54 | + if (count == 0) { |
| 55 | + break; |
| 56 | + } |
51 | 57 | } |
| 58 | + steps++; |
52 | 59 | } |
53 | 60 | } |
54 | | - memo[lastPos][remainingPawns] = result; |
55 | | - return result; |
56 | 61 | } |
57 | 62 |
|
58 | | - private int calculateMoves(int x1, int y1, int x2, int y2) { |
59 | | - if (x1 == x2 && y1 == y2) { |
60 | | - return 0; |
61 | | - } |
62 | | - boolean[][] visited = new boolean[50][50]; |
63 | | - Queue<int[]> queue = new LinkedList<>(); |
64 | | - queue.offer(new int[] {x1, y1, 0}); |
65 | | - visited[x1][y1] = true; |
66 | | - while (!queue.isEmpty()) { |
67 | | - int[] current = queue.poll(); |
68 | | - int x = current[0]; |
69 | | - int y = current[1]; |
70 | | - int moves = current[2]; |
71 | | - for (int[] move : KNIGHT_MOVES) { |
72 | | - int nx = x + move[0]; |
73 | | - int ny = y + move[1]; |
74 | | - if (nx == x2 && ny == y2) { |
75 | | - return moves + 1; |
76 | | - } |
77 | | - if (nx >= 0 && nx < 50 && ny >= 0 && ny < 50 && !visited[nx][ny]) { |
78 | | - queue.offer(new int[] {nx, ny, moves + 1}); |
79 | | - visited[nx][ny] = true; |
| 63 | + private int calculateDP(int n, int[][] distances) { |
| 64 | + int m = (1 << n) - 1; |
| 65 | + int[][] dp = new int[1 << n][n + 1]; |
| 66 | + for (int mask = 1; mask < (1 << n); mask++) { |
| 67 | + boolean isEven = (Integer.bitCount(m ^ mask)) % 2 == 0; |
| 68 | + for (int i = 0; i <= n; i++) { |
| 69 | + int result = 0; |
| 70 | + if (isEven) { |
| 71 | + for (int j = 0; j < n; j++) { |
| 72 | + if ((mask & (1 << j)) > 0) { |
| 73 | + result = Math.max(result, dp[mask ^ (1 << j)][j] + distances[i][j]); |
| 74 | + } |
| 75 | + } |
| 76 | + } else { |
| 77 | + result = Integer.MAX_VALUE; |
| 78 | + for (int j = 0; j < n; j++) { |
| 79 | + if ((mask & (1 << j)) > 0) { |
| 80 | + result = Math.min(result, dp[mask ^ (1 << j)][j] + distances[i][j]); |
| 81 | + } |
| 82 | + } |
80 | 83 | } |
| 84 | + dp[mask][i] = result; |
81 | 85 | } |
82 | 86 | } |
83 | | - // Should never reach here if input is valid |
84 | | - return -1; |
| 87 | + return dp[m][n]; |
| 88 | + } |
| 89 | + |
| 90 | + public int maxMoves(int kx, int ky, int[][] positions) { |
| 91 | + int n = positions.length; |
| 92 | + int[][] pos = new int[50][50]; |
| 93 | + initializePositions(positions, pos, kx, ky); |
| 94 | + int[][] distances = new int[n + 1][n + 1]; |
| 95 | + calculateDistances(positions, pos, distances); |
| 96 | + return calculateDP(n, distances); |
85 | 97 | } |
86 | 98 | } |
0 commit comments