二进制矩阵转全0最小正方形翻转次数求解及代码问题排查
Let's break down what's going wrong with your approach and fix it step by step. The core issues lie in how you're constructing the augmented matrix for Gaussian elimination and how you're interpreting the result after elimination.
1. Critical Flaws in Your Current Implementation
a. Misaligned Variable & Equation Setup
For a square size s, the number of variables (each representing whether we flip an s×s square) should be the count of valid top-left corners for such squares: (N - s + 1) * (M - s + 1). Your code incorrectly uses N*M variables, treating every matrix cell as a potential square origin even when it can't form an s×s square.
Worse, when a cell can't be a square origin, you copy rows from above or left—this breaks the equation logic entirely. Each row should represent an equation for a single matrix cell: the sum (mod 2) of all variables (square flips) that cover this cell must equal the original cell's value (since flipping a cell an odd number of times changes it, even leaves it the same).
b. Incorrect Result Calculation
You're counting 1s in the last column of the reduced matrix, which isn't how you get the number of operations. After Gaussian elimination, you need to back-substitute to find which variables are set to 1 (meaning we perform that square flip), then count those 1s.
2. Fixed Solution Code
Here's the corrected Java code that properly constructs the matrix and solves for the minimal operations per square size:
package com.practice.hustle; public class SquareFlipMinOperations { public static void main(String[] args) { byte[][] inputMatrix = { {0, 1, 1}, {0, 0, 0}, {0, 1, 1} }; int N = inputMatrix.length; int M = inputMatrix[0].length; int minOperations = Integer.MAX_VALUE; // Check all possible square sizes from 1 to max possible int maxSquareSize = Math.min(N, M); for (int s = 1; s <= maxSquareSize; s++) { int varCount = (N - s + 1) * (M - s + 1); int equationCount = N * M; // Build augmented matrix: equationCount rows, varCount + 1 columns byte[][] augMatrix = new byte[equationCount][varCount + 1]; for (int i = 0; i < N; i++) { for (int j = 0; j < M; j++) { int rowIdx = i * M + j; augMatrix[rowIdx][varCount] = inputMatrix[i][j]; // Mark all variables (squares) that cover cell (i,j) for (int x = Math.max(0, i - s + 1); x <= i; x++) { for (int y = Math.max(0, j - s + 1); y <= j; y++) { // Check if (x,y) is a valid top-left corner for s×s square if (x + s <= N && y + s <= M) { int varIdx = x * (M - s + 1) + y; augMatrix[rowIdx][varIdx] = (byte) (augMatrix[rowIdx][varIdx] ^ 1); } } } } } int operations = solveGaussianGF2(augMatrix, equationCount, varCount); if (operations != -1) { // Ignore if no solution (though 1x1 always has solution) minOperations = Math.min(minOperations, operations); } } System.out.println("Minimum operations needed: " + minOperations); } // Solve GF(2) Gaussian elimination and return minimal number of 1s in solution private static int solveGaussianGF2(byte[][] augMatrix, int rows, int cols) { int rank = 0; int[] colToRow = new int[cols]; // Maps column to pivot row for (int i = 0; i < cols; i++) colToRow[i] = -1; // Forward elimination for (int col = 0; col < cols && rank < rows; col++) { // Find pivot row int pivotRow = -1; for (int row = rank; row < rows; row++) { if (augMatrix[row][col] == 1) { pivotRow = row; break; } } if (pivotRow == -1) continue; // Swap pivot row with current rank row byte[] temp = augMatrix[rank]; augMatrix[rank] = augMatrix[pivotRow]; augMatrix[pivotRow] = temp; colToRow[col] = rank; // Eliminate this column in all other rows for (int row = 0; row < rows; row++) { if (row != rank && augMatrix[row][col] == 1) { for (int c = col; c <= cols; c++) { augMatrix[row][c] = (byte) (augMatrix[row][c] ^ augMatrix[rank][c]); } } } rank++; } // Check for inconsistent system for (int row = rank; row < rows; row++) { if (augMatrix[row][cols] == 1) { return -1; // No solution } } // Back-substitute to find minimal solution (set free variables to 0) byte[] solution = new byte[cols]; for (int col = 0; col < cols; col++) { if (colToRow[col] != -1) { int row = colToRow[col]; solution[col] = augMatrix[row][cols]; for (int c = col + 1; c < cols; c++) { if (augMatrix[row][c] == 1) { solution[col] ^= solution[c]; } } } } // Count number of 1s in solution (operations needed) int count = 0; for (byte b : solution) { if (b == 1) count++; } return count; } }
3. Key Fixes Explained
- Correct Matrix Construction: For each cell
(i,j), we mark alls×ssquares that cover it, building a valid equation for the cell's required flip count. - Proper GF(2) Gaussian Elimination: Implements binary field arithmetic (XOR for addition/subtraction) and handles free variables by setting them to 0 to get the minimal operation count.
- Full Range of Square Sizes: Checks all square sizes from 1 to the maximum possible, ensuring we find the minimal operations across all valid square sizes.
Running this code with your sample input will output 2, which matches the expected minimal operations using 2×2 squares.
内容的提问来源于stack exchange,提问作者javaGroup456

