https://school.programmers.co.kr/learn/courses/30/lessons/131703
이 문제의 핵심은 이미 뒤집은 열 혹은 행은 다시 뒤집지 않아도 된다는 것이다.
2 ^ H, 열을 뒤집는 경우의 수인 2 ^ W 의 경우의 수를 곱한 경우의 수가 존재한다. ex) H = 10, W = 10 총 경우의 수 = 2 ^ 2010/101 이면, 첫번째 행을 뒤집고, 첫번째 열, 세번째 열을 뒤집는 것이다. (00000 ~ 11111, 0 ~ 31, 2 ^ H * 2 ^ W)O((2 ^ H) * (2 ^ W) * H * W)
import java.util.*;
class Solution {
public int H;
public int W;
public int[][] b;
public int[][] t;
public int parsing(int number) { // 비트를 파싱하는 메서드
int count = 0; // 뒤집은 횟수를 기록
int[][] c = new int[H][W]; // beggining 을 복사한 배열
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
c[i][j] = b[i][j];
}
} // 복사
for (int i = 0; (1 << i) <= number; i++) {
if ((number & (1 << i)) != 0) { // 뒤집어야 하는 경우
count++; // 뒤집은 횟수를 기록
change(c, i); // 실제로 뒤집는 행위
}
}
if (equal(c)) { // 뒤집은 결과가 target 과 동일한지 검증
return count; // 동일하다면 뒤집은 횟수를 반환
}
return Integer.MAX_VALUE; // 해당 비트로는 동일한 결과를 만들 수 없다면 invalid 한 값 반환
}
public void change(int[][] c, int digit) {
if (digit < H) { // digit 이 H 보다 작다면 행을 뒤집는다
changeRow(c, digit);
} else { // digit 이 H 보다 크거나 같다면 열을 뒤집는다.
changeCol(c, digit - H);
}
}
public boolean equal(int[][] c) { // 두개의 배열이 같은지 비교하는 연산
for (int i = 0; i < H; i++) {
for (int j = 0; j < W; j++) {
if (c[i][j] != t[i][j]) {
return false;
}
}
}
return true;
}
public void changeRow(int[][] c, int row) { // 행을 뒤집는 연산
for (int i = 0; i < W; i++) {
c[row][i] = (c[row][i] + 1) % 2;
}
}
public void changeCol(int[][] c, int col) { // 열을 뒤집는 연산
for (int i = 0; i < H; i++) {
c[i][col] = (c[i][col] + 1) % 2;
}
}
public int solution(int[][] beginning, int[][] target) {
this.H = beginning.length;
this.W = beginning[0].length;
this.b = beginning;
this.t = target;
int total = (int) Math.pow(2, H) * (int) Math.pow(2, W); // 전체 경우의 수를 구함
int answer = Integer.MAX_VALUE;
for (int i = 0; i < total; i++) {
answer = Math.min(answer, parsing(i)); // parsing 하면서 가장 작은 값 골라냄
}
return answer == Integer.MAX_VALUE ? -1 : answer; // 맞추지 못하는 경우 -1 반환
}
}