From 3ff7ec6b5bea786ebbaad2b5b3a5f3673c5b3c77 Mon Sep 17 00:00:00 2001 From: Valentyn Kolesnikov Date: Sat, 22 Mar 2025 09:33:00 +0200 Subject: [PATCH] Improved task 3283 --- .../Solution.java | 136 ++++++++++-------- 1 file changed, 74 insertions(+), 62 deletions(-) diff --git a/src/main/java/g3201_3300/s3283_maximum_number_of_moves_to_kill_all_pawns/Solution.java b/src/main/java/g3201_3300/s3283_maximum_number_of_moves_to_kill_all_pawns/Solution.java index d971640a3..5fa4cdda6 100644 --- a/src/main/java/g3201_3300/s3283_maximum_number_of_moves_to_kill_all_pawns/Solution.java +++ b/src/main/java/g3201_3300/s3283_maximum_number_of_moves_to_kill_all_pawns/Solution.java @@ -1,86 +1,98 @@ package g3201_3300.s3283_maximum_number_of_moves_to_kill_all_pawns; // #Hard #Array #Math #Breadth_First_Search #Bit_Manipulation #Bitmask #Game_Theory -// #2024_09_09_Time_250_ms_(98.43%)_Space_50.1_MB_(66.27%) +// #2025_03_22_Time_126_ms_(100.00%)_Space_48.23_MB_(72.09%) -import java.util.LinkedList; +import java.util.ArrayDeque; import java.util.Queue; public class Solution { - private static final int[][] KNIGHT_MOVES = { - {-2, -1}, {-2, 1}, {-1, -2}, {-1, 2}, - {1, -2}, {1, 2}, {2, -1}, {2, 1} + private static final int[][] DIRECTIONS = { + {2, 1}, {1, 2}, {-1, 2}, {-2, 1}, {-2, -1}, {-1, -2}, {1, -2}, {2, -1} }; - private int[][] distances; - private Integer[][] memo; - public int maxMoves(int kx, int ky, int[][] positions) { + private void initializePositions(int[][] positions, int[][] pos, int kx, int ky) { int n = positions.length; - distances = new int[n + 1][n + 1]; - memo = new Integer[n + 1][1 << n]; - // Calculate distances between all pairs of positions (including knight's initial position) for (int i = 0; i < n; i++) { - distances[n][i] = calculateMoves(kx, ky, positions[i][0], positions[i][1]); - for (int j = i + 1; j < n; j++) { - int dist = - calculateMoves( - positions[i][0], positions[i][1], positions[j][0], positions[j][1]); - distances[i][j] = distances[j][i] = dist; - } + int x = positions[i][0]; + int y = positions[i][1]; + pos[x][y] = i; } - return minimax(n, (1 << n) - 1, true); + pos[kx][ky] = n; } - private int minimax(int lastPos, int remainingPawns, boolean isAlice) { - if (remainingPawns == 0) { - return 0; - } - if (memo[lastPos][remainingPawns] != null) { - return memo[lastPos][remainingPawns]; - } - int result = isAlice ? 0 : Integer.MAX_VALUE; - for (int i = 0; i < distances.length - 1; i++) { - if ((remainingPawns & (1 << i)) != 0) { - int newRemainingPawns = remainingPawns & ~(1 << i); - int moveValue = distances[lastPos][i] + minimax(i, newRemainingPawns, !isAlice); - - if (isAlice) { - result = Math.max(result, moveValue); - } else { - result = Math.min(result, moveValue); + private void calculateDistances(int[][] positions, int[][] pos, int[][] distances) { + int n = positions.length; + for (int i = 0; i < n; i++) { + int count = n - i; + boolean[][] visited = new boolean[50][50]; + visited[positions[i][0]][positions[i][1]] = true; + Queue que = new ArrayDeque<>(); + que.offer(new int[] {positions[i][0], positions[i][1]}); + int steps = 1; + while (!que.isEmpty() && count > 0) { + int size = que.size(); + while (size-- > 0) { + int[] cur = que.poll(); + int x = cur[0]; + int y = cur[1]; + for (int[] d : DIRECTIONS) { + int nx = x + d[0]; + int ny = y + d[1]; + if (0 <= nx && nx < 50 && 0 <= ny && ny < 50 && !visited[nx][ny]) { + que.offer(new int[] {nx, ny}); + visited[nx][ny] = true; + int j = pos[nx][ny]; + if (j > i) { + distances[i][j] = distances[j][i] = steps; + if (--count == 0) { + break; + } + } + } + } + if (count == 0) { + break; + } } + steps++; } } - memo[lastPos][remainingPawns] = result; - return result; } - private int calculateMoves(int x1, int y1, int x2, int y2) { - if (x1 == x2 && y1 == y2) { - return 0; - } - boolean[][] visited = new boolean[50][50]; - Queue queue = new LinkedList<>(); - queue.offer(new int[] {x1, y1, 0}); - visited[x1][y1] = true; - while (!queue.isEmpty()) { - int[] current = queue.poll(); - int x = current[0]; - int y = current[1]; - int moves = current[2]; - for (int[] move : KNIGHT_MOVES) { - int nx = x + move[0]; - int ny = y + move[1]; - if (nx == x2 && ny == y2) { - return moves + 1; - } - if (nx >= 0 && nx < 50 && ny >= 0 && ny < 50 && !visited[nx][ny]) { - queue.offer(new int[] {nx, ny, moves + 1}); - visited[nx][ny] = true; + private int calculateDP(int n, int[][] distances) { + int m = (1 << n) - 1; + int[][] dp = new int[1 << n][n + 1]; + for (int mask = 1; mask < (1 << n); mask++) { + boolean isEven = (Integer.bitCount(m ^ mask)) % 2 == 0; + for (int i = 0; i <= n; i++) { + int result = 0; + if (isEven) { + for (int j = 0; j < n; j++) { + if ((mask & (1 << j)) > 0) { + result = Math.max(result, dp[mask ^ (1 << j)][j] + distances[i][j]); + } + } + } else { + result = Integer.MAX_VALUE; + for (int j = 0; j < n; j++) { + if ((mask & (1 << j)) > 0) { + result = Math.min(result, dp[mask ^ (1 << j)][j] + distances[i][j]); + } + } } + dp[mask][i] = result; } } - // Should never reach here if input is valid - return -1; + return dp[m][n]; + } + + public int maxMoves(int kx, int ky, int[][] positions) { + int n = positions.length; + int[][] pos = new int[50][50]; + initializePositions(positions, pos, kx, ky); + int[][] distances = new int[n + 1][n + 1]; + calculateDistances(positions, pos, distances); + return calculateDP(n, distances); } }