728x90
728x90

문제

지민이는 자신의 저택에서 MN개의 단위 정사각형으로 나누어져 있는 M×N 크기의 보드를 찾았다. 어떤 정사각형은 검은색으로 칠해져 있고, 나머지는 흰색으로 칠해져 있다. 지민이는 이 보드를 잘라서 8×8 크기의 체스판으로 만들려고 한다.

체스판은 검은색과 흰색이 번갈아서 칠해져 있어야 한다. 구체적으로, 각 칸이 검은색과 흰색 중 하나로 색칠되어 있고, 변을 공유하는 두 개의 사각형은 다른 색으로 칠해져 있어야 한다. 따라서 이 정의를 따르면 체스판을 색칠하는 경우는 두 가지뿐이다. 하나는 맨 왼쪽 위 칸이 흰색인 경우, 하나는 검은색인 경우이다.

보드가 체스판처럼 칠해져 있다는 보장이 없어서, 지민이는 8×8 크기의 체스판으로 잘라낸 후에 몇 개의 정사각형을 다시 칠해야겠다고 생각했다. 당연히 8*8 크기는 아무데서나 골라도 된다. 지민이가 다시 칠해야 하는 정사각형의 최소 개수를 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 N과 M이 주어진다. N과 M은 8보다 크거나 같고, 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에는 보드의 각 행의 상태가 주어진다. B는 검은색이며, W는 흰색이다.

 

출력

첫째 줄에 지민이가 다시 칠해야 하는 정사각형 개수의 최솟값을 출력한다.

 

예제 입력 1 

8 8
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBBBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW

 

예제 출력 1

1

 

예제 입력 2

10 13
BBBBBBBBWBWBW
BBBBBBBBBWBWB
BBBBBBBBWBWBW
BBBBBBBBBWBWB
BBBBBBBBWBWBW
BBBBBBBBBWBWB
BBBBBBBBWBWBW
BBBBBBBBBWBWB
WWWWWWWWWWBWB
WWWWWWWWWWBWB

 

예제 출력 2

12

 

예제 입력 3

8 8
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBWBWBW
WBWBWBWB

 

예제 출력 3

0

 

예제 입력 4

9 23
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBW

 

예제 출력 4

31

 

예제 입력 5

10 10
BBBBBBBBBB
BBWBWBWBWB
BWBWBWBWBB
BBWBWBWBWB
BWBWBWBWBB
BBWBWBWBWB
BWBWBWBWBB
BBWBWBWBWB
BWBWBWBWBB
BBBBBBBBBB

 

예제 출력 5

0

 

예제 입력 6

8 8
WBWBWBWB
BWBWBWBW
WBWBWBWB
BWBBBWBW
WBWBWBWB
BWBWBWBW
WBWBWWWB
BWBWBWBW

 

예제 출력 6

2

 

예제 입력 7

11 12
BWWBWWBWWBWW
BWWBWBBWWBWW
WBWWBWBBWWBW
BWWBWBBWWBWW
WBWWBWBBWWBW
BWWBWBBWWBWW
WBWWBWBBWWBW
BWWBWBWWWBWW
WBWWBWBBWWBW
BWWBWBBWWBWW
WBWWBWBBWWBW

 

예제 출력 7

15

 

알고리즘 분류

  • 브루트포스 알고리즘

 

문제 출처

https://www.acmicpc.net/problem/1018

 

1018번: 체스판 다시 칠하기

첫째 줄에 N과 M이 주어진다. N과 M은 8보다 크거나 같고, 50보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에는 보드의 각 행의 상태가 주어진다. B는 검은색이며, W는 흰색이다.

www.acmicpc.net

 


 

문제 해결 방법

  • 처음에는 이렇게 무식한 방법으로 풀려고 했으나...
bool check[8][8];

int findNumOfSquares(char board[][9]) {    // 매개 변수로 2차원 배열 사용하기
    int cnt;

    // 잘못된 곳을 찾아서 새로 칠하기
    cnt = 0;
    for (int p = 0; p < 7; p++) {
        for (int q = 0; q < 7; q++) {
            if (board[p][q] == 'W') {
                if (board[p + 1][q] == 'W') {      // 세로줄 판별
                   board[p + 1][q] = 'B';          // 페인트 칠하기
                   check[p + 1][q] = true;         // 표시하기
                }
                else {
                    if (board[p][q + 1] == 'W') {  // 가로줄 판별
                        board[p][q + 1] = 'B';     // 페인트 칠하기
                        check[p][q + 1] = true;    // 표시하기
                    }
                }
            }
            else {
                if (board[p + 1][q] == 'B') {     // 세로줄 판별
                    board[p + 1][q] = 'W';        // 페인트 칠하기
                    check[p + 1][q] = true;       // 표시하기
                }
                else {
                    if (board[p][q + 1] == 'B') {  // 가로줄 판별
                        board[p][q + 1] = 'W';     // 페인트 칠하기
                        check[p][q + 1] = true;    // 표시하기
                    }
                }
            }
        }
    }
    
    // 최솟값 구하기
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (check[i][j] != 0) {
                cnt++;
            }
        }
    }

    return cnt;
}

 

  • 문제에 정답인 경우가 제시되어 있고, 배열의 요소를 비교하는 방법을 사용하면 쉽게 문제를 풀 수 있겠다는 생각이 들었다.
  • 그래서 8x8 체스판이 만들어질 수 있는 2가지 경우의 2차원 배열(type1, type2)을 미리 만들어주고, 입력 받은 2차원 배열(board)에서 8x8 배열을 뽑아내서 새로운 배열(chessboard)을 생성한 다음, 각 배열(board, chessboard)에서 0에서 7까지 인덱스의 값이 서로 비슷한지를 판별하는 방식으로 문제를 해결하였다.
왼쪽 상단 위가 흰색(W)으로 시작하는 경우 (type1) 왼쪽 상단 위가 검정색(B)으로 시작하는 경우 (type2)
□■□■□■□■
■□■□■□■□
□■□■□■□■
■□■□■□■□
□■□■□■□■
■□■□■□■□
□■□■□■□■
■□■□■□■□
■□■□■□■□
□■□■□■□■
■□■□■□■□
□■□■□■□■
■□■□■□■□
□■□■□■□■
■□■□■□■□
□■□■□■□■
char type1[8][8] = { { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' }};

char type2[8][8] = { { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },    
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' } };

 

  •  우선 다음과 같이 4중 for 문(2중 for 문 -> 기본 배열에 접근, 2중 for 문 -> 옮길 배열에 접근)을 이용하여 입력을 받은 2차원 배열(board)에서 8x8 크기 만큼 요소를 뽑아내어 새로운 8x8 행렬(chessBoard)에 넣었다.
    • 요소를 옮길 범위를 신경써서 체크해줘야 했다. (i + 8 <= n, j + 8 <= m)
for (int i = 0; i + 8 <= n; i++) {
    for (int j = 0; j + 8 <= m; j++) {
        for (int k = 0; k < 8; k++) {
            for (int l = 0; l < 8; l++) {
                chessBoard[k][l] = board[i + k][j + l];
            }
        }
    }
}

 

  •  왼쪽 상단 위가 'W'로 시작할 경우(type1)와 왼쪽 상단 위가 'B'로 시작할 경우(type2)의 배열과 chessBoard 배열의 요소를 비교하면서, 요소가 서로 다르면 cnt 변수의 값을 하나씩 증가시켜주었다.
  • 그리고 각각의 경우의 값(cnt1, cnt2)의 크기 중 최소값을 반환하도록 하였다.
int findNumOfSquares(char board[][8]) {    // 매개 변수로 2차원 배열 사용하기
    int cnt1, cnt2, minNum;

    cnt1 = 0;
    cnt2 = 0;

    // type1 체크 : 왼쪽 상단 위가 W로 시작할 경우
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (board[i][j] != type1[i][j]) {
                cnt1++;
            }
        }
    }

    // type2 체크 : 왼쪽 상단 위가 B로 시작할 경우
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (board[i][j] != type2[i][j]) {
                cnt2++;
            }
        }
    }

    minNum = min(cnt1, cnt2);

    return minNum;
}

 

  • 이 과정이 3번째 for 문이 끝난 후(board 배열에서 chessBoard 배열로 요소를 모두 옮긴 후) 바로 바로 이루어지도록 하였고, 반환된 값(최소값)이 벡터 컨테이너(nums)에 차례로 삽입되도록 하였다.
  • 그리고 sort() 함수를 이용하여 nums에 있는 요소들을 오름차순으로 정렬해주었다. (이 때, 최솟값 nums[0]에 위치하게 된다.)
  • 따라서 nums[0]이 이 문제의 정답이 된다.
int BruteForce(int n, int m) {
    for (int i = 0; i + 8 <= n; i++) {
        for (int j = 0; j + 8 <= m; j++) {
            for (int k = 0; k < 8; k++) {
                for (int l = 0; l < 8; l++) {
                    chessBoard[k][l] = board[i + k][j + l];
                }
            }
            nums.push_back(findNumOfSquares(chessBoard));
        }
    }

    sort(nums.begin(), nums.end());    // 오름차순 정렬

    return nums[0];
}

 

  • 참고로, 2차원 배열을 인자로 전달 받으려면 다음과 같이 함수의 매개 변수를 설정해주어야 한다.
    • 2차원 배열의 가로 열의 크기(N)를 반드시 넣어주어야 한다.
int ary(int ary[][N]) {
    // 내용
}

 

코드

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int N, M;
vector<int> nums;
char board[51][51], chessBoard[8][8];
char type1[8][8] = { { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' }};

char type2[8][8] = { { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },    
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' },
                     { 'B', 'W', 'B', 'W', 'B', 'W', 'B', 'W' },
                     { 'W', 'B', 'W', 'B', 'W', 'B', 'W', 'B' } };


int findNumOfSquares(char board[][8]) {    // 매개 변수로 2차원 배열 사용하기
    int cnt1, cnt2, minNum;

    cnt1 = 0;
    cnt2 = 0;

    // type1 체크 : 왼쪽 상단 위가 W로 시작할 경우
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (board[i][j] != type1[i][j]) {
                cnt1++;
            }
        }
    }

    // type2 체크 : 왼쪽 상단 위가 B로 시작할 경우
    for (int i = 0; i < 8; i++) {
        for (int j = 0; j < 8; j++) {
            if (board[i][j] != type2[i][j]) {
                cnt2++;
            }
        }
    }

    minNum = min(cnt1, cnt2);

    return minNum;
}

int BruteForce(int n, int m) {
    for (int i = 0; i + 8 <= n; i++) {
        for (int j = 0; j + 8 <= m; j++) {
            for (int k = 0; k < 8; k++) {
                for (int l = 0; l < 8; l++) {
                    chessBoard[k][l] = board[i + k][j + l];
                }
            }
            nums.push_back(findNumOfSquares(chessBoard));
        }
    }

    sort(nums.begin(), nums.end());    // 오름차순 정렬

    return nums[0];
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    cin >> N >> M;    // N x M (행 : N, 열 : M)

    for (int i = 0; i < N; i++) {
        for (int j = 0; j < M; j++) {
            cin >> board[i][j];
        }
    }
    
    cout << BruteForce(N, M) << endl;

    return 0;
}

 

채점 결과

 

참고

  • [단계별로 풀어보기] > [브루트 포스]
  • 실버IV

 

728x90
728x90