지민이는 자신의 저택에서 MN개의 단위 정사각형으로 나누어져 있는 M×N 크기의 보드를 찾았다. 어떤 정사각형은 검은색으로 칠해져 있고, 나머지는 흰색으로 칠해져 있다. 지민이는 이 보드를 잘라서 8×8 크기의 체스판으로 만들려고 한다.
체스판은 검은색과 흰색이 번갈아서 칠해져 있어야 한다. 구체적으로, 각 칸이 검은색과 흰색 중 하나로 색칠되어 있고, 변을 공유하는 두 개의 사각형은 다른 색으로 칠해져 있어야 한다. 따라서 이 정의를 따르면 체스판을 색칠하는 경우는 두 가지뿐이다. 하나는 맨 왼쪽 위 칸이 흰색인 경우, 하나는 검은색인 경우이다.
보드가 체스판처럼 칠해져 있다는 보장이 없어서, 지민이는 8×8 크기의 체스판으로 잘라낸 후에 몇 개의 정사각형을 다시 칠해야겠다고 생각했다. 당연히 8*8 크기는 아무데서나 골라도 된다. 지민이가 다시 칠해야 하는 정사각형의 최소 개수를 구하는 프로그램을 작성하시오.
첫째 줄에 N과 M이 주어진다. N과 M은 8보다 크거나 같고, 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에는 보드의 각 행의 상태가 주어진다. B는 검은색이며, W는 흰색이다.
첫째 줄에 지민이가 다시 칠해야 하는 정사각형 개수의 최솟값을 출력한다.
8 8
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBBBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW
1
10 13
BBBBBBBBWBWBW
BBBBBBBBBWBWB
BBBBBBBBWBWBW
BBBBBBBBBWBWB
BBBBBBBBWBWBW
BBBBBBBBBWBWB
BBBBBBBBWBWBW
BBBBBBBBBWBWB
WWWWWWWWWWBWB
WWWWWWWWWWBWB
12
8 8
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
0
9 23
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBW
31
10 10
BBBBBBBBBB
BBWBWBWBWB
BWBWBWBWBB
BBWBWBWBWB
BWBWBWBWBB
BBWBWBWBWB
BWBWBWBWBB
BBWBWBWBWB
BWBWBWBWBB
BBBBBBBBBB
0
8 8
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBBBWBW
WBWBWBWB
BWBWBWBW
WBWBWWWB
BWBWBWBW
2
11 12
BWWBWWBWWBWW
BWWBWBBWWBWW
WBWWBWBBWWBW
BWWBWBBWWBWW
WBWWBWBBWWBW
BWWBWBBWWBWW
WBWWBWBBWWBW
BWWBWBWWWBWW
WBWWBWBBWWBW
BWWBWBBWWBWW
WBWWBWBBWWBW
15
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class BJ1018 {
public static void main(String[] args) throws IOException {
char[][] bw={{'W','B','W','B','W','B','W','B'},{'B','W','B','W','B','W','B','W'}};
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st=new StringTokenizer(br.readLine());
int N=Integer.parseInt(st.nextToken());
int M=Integer.parseInt(st.nextToken());
char[][] board=new char[N][M];
for(int i=0;i<N;i++){
board[i]=br.readLine().toCharArray();
}
int cnt=Integer.MAX_VALUE;
for(int i=0;i<N-7;i++){
for(int j=0;j<M-7;j++){
int tmp1=0;
int tmp2=0;
for (int k = 0; k < 8; k++) {
for (int m = 0; m < 8; m++) {
if(board[i+k][j+m]!=bw[(k+1)%2][m]) tmp1++;
if(board[i+k][j+m]!=bw[k%2][m]) tmp2++;
}
}
cnt=Math.min(cnt,tmp1);
cnt=Math.min(cnt,tmp2);
}
}
System.out.println(cnt);
}
}
8x8 크기의 체스판을 비교하고 색을 바꿔야하는 체스판의 최소 개수를 구하는 문제이다.
비교해야하는 체스판의 크기가 8x8로 정해져있기 때문에 한 줄에 놓일 수 있는 체스들의 경우는 두 가지뿐이다.
때문에 두 가지 경우를 배열 변수에 값을 넣어주어 조금 더 쉽게 비교할 수 있도록 한다.
완전탐색
int cnt=Integer.MAX_VALUE;
for(int i=0;i<N-7;i++){
for(int j=0;j<M-7;j++){
int tmp1=0;
int tmp2=0;
for (int k = 0; k < 8; k++) {
for (int m = 0; m < 8; m++) {
if(board[i+k][j+m]!=bw[(k+1)%2][m]) tmp1++;
if(board[i+k][j+m]!=bw[k%2][m]) tmp2++;
}
}
cnt=Math.min(cnt,tmp1);
cnt=Math.min(cnt,tmp2);
}
}
정답을 위한 변수 cnt
를 정의하고 최소값을 구해야하기 때문에 Integer.MAX_VALUE로 초기화해준다.
입력으로 받은 체스판의 정보를 기반으로 시작점을 한 칸씩 이동하여 8x8의 경우를 모두 탐색해본다.
즉, for문은 각각 N-7
,M-7
까지 반복하고 i+k
, j+m
을 인덱스로 주어 시작점에서부터 가로,세로로 8칸까지 비교한다.
시작점으로 부터 가로, 세로로 8칸까지 확인이 가능해야 8x8 체스판을 비교하고 만들 수 있기 때문이다.
해당 시작점으로부터 8x8 크기의 체스판을 비교하는데 B
로 시작하게되는 경우와 W
로 시작하게되는 경우 모두 확인해보고 최소값을 구해야한다.
이전에 만들어둔 배열값과 나머지 연산을 이용하여 다른 체스가 있다면 tmp1
혹은 tmp2
카운트를 증가시켜준다.
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW
위와 같이 B
로 시작하는 체스판, W
로 시작하는 체스판의 경우이다. 문제에 주어진대로 이전행의 체스가 BWBW...
로 시작된다면 다음행은 WBWB...
로 이루어져있다.
그리고 처음에 선언한 배열값은 2행까지 존재한다.
char[][] bw={{'W','B','W','B','W','B','W','B'},{'B','W','B','W','B','W','B','W'}};
이런 경우에는 행의 값을 8까지 증가시켜주고 나머지 연산을 이용하여 bw
의 0
행과 1
행을 선택할 수 있다.
if(board[i+k][j+m]!=bw[(k+1)%2][m]) tmp1++;
if(board[i+k][j+m]!=bw[k%2][m]) tmp2++;
이때, 하나의 경우만 비교할게 아니라 B
로 시작하는 경우, W
로 시작하는 경우 모두 비교해줘야하기 때문에 인덱스를 k+1
로 해주어 두 가지 경우를 한번에 비교하여 체스의 색을 바꿔야하는 횟수를 tmp1
, tmp2
변수에 담아준다.
모든 비교가 끝나면 cnt
와 tmp1
, tmp2
의 값을 비교하여 최소값을 갱신해주면 답을 도출할 수 있다.