[백준 문제 풀이] 1018번 체스판 다시 칠하기

Junu Kim·2025년 12월 23일
post-thumbnail

[1018] 체스판 다시 칠하기

난이도: ★★★☆☆ • solved on: 2025-12-23


문제 요약

  • 문제 유형: 완전탐색 (Brute Force), 2D 배열, 구현
  • 요구사항: N×M 보드에서 임의의 8×8 부분을 골라 체스판 패턴(좌상단이 B 시작 또는 W 시작)으로 만들기 위해 다시 칠해야 하는 칸의 최소 개수를 출력해야 한다.

사용 개념

  1. 자료구조

    • 2차원 배열(String[][])
    • 문자열 배열(String[])
  2. 알고리즘/기법

    • 8×8 모든 부분 보드 탐색
    • 두 가지 정답 패턴 (Black-start / White-start) 비교
  3. 핵심 키워드

    • 마스킹 (masking)
    • 패턴 비교 (pattern matching)
    • 슬라이딩 윈도우 (window over 2D)

풀이 아이디어

  1. 문제 분해
  • 체스판의 올바른 정답 형태는 딱 2개뿐이다.

    • (1) 좌상단이 B인 체스판
    • (2) 좌상단이 W인 체스판
  • 따라서 각 8×8 영역마다,

    • B 시작 패턴으로 만들 때의 변경 수
    • W 시작 패턴으로 만들 때의 변경 수
      를 구해서 더 작은 값을 취하고, 전체 중 최솟값을 갱신하면 된다.
  1. 핵심 로직 흐름

    for each (top-left) of 8x8:
        count_B_start = mismatches with "B start" pattern
        count_W_start = mismatches with "W start" pattern
        answer = min(answer, min(count_B_start, count_W_start))
  2. 예외 처리

    • i, j 범위는 m-8, n-8 이하(<=) 로 잡아야 8×8 딱 맞는 경우도 검사된다.

코드

import java.util.*;
import java.lang.*;
import java.io.*;

class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // "WBWBWBWB" "BWBWBWBW"
        String[] sizes = sc.nextLine().split(" ");
        int n = Integer.parseInt(sizes[1]);
        int m = Integer.parseInt(sizes[0]);
        String[][] sample =  new String[m][n];
        String[] line = new String[n];
        int result = -1;
        for(int i = 0; i < m; i++){
            line = sc.nextLine().split("");
            for(int j = 0; j < n; j++){
                sample[i][j] = line[j];
            }
        }
        String[] rowBlack =  "BWBWBWBW".split("");
        String[] rowWhite =  "WBWBWBWB".split("");

        for(int i =0; i <= m-8; i++){
            for(int j =0; j <= n-8; j++){
                int[][] changes = new int[2][8];
                for(int k = 0; k < 8; k++){
                    for(int l = 0; l < 8; l++){
                        if(!sample[k+i][l+j].equals(rowBlack[l])){
                            changes[k%2][k] += 1;
                        } else {
                            changes[k%2][k] += 0;
                        }
                        if(!sample[k+i][l+j].equals(rowWhite[l])){
                            changes[(k+1)%2][k] += 1;
                        } else {
                            changes[(k+1)%2][k] += 0;
                        }
                    }
                }
                int tmp = Math.min(Arrays.stream(changes[0]).sum(), Arrays.stream(changes[1]).sum());
                if(result == -1){
                    result = tmp;
                } else {
                    result = Math.min(result, tmp);
                }
            }
        }
        System.out.println(result);
    }
}

시간·공간 복잡도

  • 시간 복잡도: O((N-7)(M-7) * 64)O(NM)

    • 모든 시작점에 대해 8×8=64칸만 검사 (상수)
  • 공간 복잡도: O(NM)

    • 입력 보드를 String[][]로 저장
    • 부분 계산용 changes는 상수 크기

어려웠던 점

  • 처음에 “무엇을 기준으로 바꿔야 하는지”를 정의하는 게 어려웠다.
  • 정답 패턴이 (검정 시작 / 하양 시작) 두 가지뿐이라는 점에 집중해 마스킹 검정으로 해결했다.
  • 좌상단 시작 색에 따라 행 인덱스 짝/홀(k%2)이 자동으로 섞인다는 아이디어로 두 패턴을 동시에 검증했다.
  • i, j 범위를 < m-8, < n-8로 잡으면 8×8 입력에서 아예 실행이 안 되는 문제를 통해 <=가 맞음을 발견했다.

배운 점 및 팁

  • 체스판 문제는 “정답 패턴이 2개뿐”이라는 사실을 먼저 고정하면 구현이 단순해진다.
    • 앞으로는 복잡해 보이는 문제에 대해 최대한 단순하게 분류하는 연습을 해야겠다는 생각이 든 문제
  • 8×8처럼 고정 크기 검사는, 전체 복잡도가 NM에 비례하더라도 실제로는 충분히 빠르다.

참고 및 링크


추가 연습 문제

profile
생각이 현실이 될 수 있도록 노력하는 중입니다.

0개의 댓글