백준의 체스판 다시 칠하기(1018) 문제이다.

( 문제 바로가기 )


[ 문제풀이 ]

1) 이 문제는 주어진 맵에서 8x8 크기만큼 떼어냈을 때, 다시 칠해야 하는 정사각형의 수의 최솟값을 구하는 문제이다.

   체스판은 가장 왼쪽 위가 흰색인 판이있고, 검정색인 판이 있다.

   즉, 우리는 이 문제를 해결하기위해서 떼어낼 수 있는 모든 8x8크기의 판에서, 가장 왼쪽 위가 흰색인 판일때의 최솟값과

   가장 왼쪽위가 검은색 판일때의 최솟값을 비교해서 더 작은 값을 정답으로 갱신해 주면석 반복하면 된다.


2) 그렇다면 맵에서 8 x 8을 어떻게 떼어내올까?? 사실상 for문을 통해서 모든 정점을 통해서 8x8 판을 떼어내오면 된다.

   여기서 정점이라는 것은 8 x 8 크기로 나눴을 때 가장 왼쪽 위 좌표를 의미한다.

   물론, 해당 정점에서 가로 세로로 8칸씩 더했을 때, 맵의 범위를 벗어나버리는 정점이라면, 그 정점에 대해서는 진행을

   하지 않아도 된다.

   우리가 해야할 것을 깔끔하게 정리해보자.

   1. 모든 정점을 돌면서, 해당 정점이 8x8 크기의 판을 만들 수 있는 정점인지 ?

   2. 가장 왼쪽 위의 좌표를 흰색으로 두었을 때 다시 칠해야 할 정사각형의 갯수가 몇개인지?

   3. 가장 왼쪽 위의 좌표를 검은색으로 두었을 때 다시 칠해야 할 정사각형의 갯수가 몇개인지?

   위의 3가지를 코드로 나타내면 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
for (int i = 0; i < N; i++)
    {
        if (i + 8 > N) break;
        for (int j = 0; j < M; j++)
        {
            if (j + 8 > M) break;
 
            White_First_Min = Make_White_First(i, j);
            Black_First_Min = Make_Black_First(i, j);
            Total_Min = Min(Total_Min, Min(White_First_Min, Black_First_Min));
        }
    }
cs


3) 그렇다면 가장 왼쪽 위의 좌표가 흰색일 때, 검은색일 때, 다시 칠해야 할 정사각형의 갯수를 Count하는 방법을 알아보자.

  

   이렇게 2개의 판이 있다. 먼저 왼쪽 위가 흰색인 판부터 보자.

   보면, 0을 포함한 짝수행에서는 짝수 열일 때 흰색. 홀수행에서는 홀수 열일 때 흰색이라는 것을 찾을 수 있다.

   (0, 0), (2, 0), (2, 2) = 흰색.

   (1, 1), (3, 5), (7, 7) = 흰색

   반면 검은색은, 0을 포함한 짝수 행에서 홀수 열일 때 검은색. 홀수 행에서는 짝수 열일때 검은색이다.

   위의 내용을 코드로 구현하면 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
for (int i = x; i < x + 8; i++)
    {
        for (int j = y; j < y + 8; j++)
        {
            if (i == x || i == x + 2 || i == x + 4 || i == x + 6)
            {
                if (j == y || j == y + 2 || j == y + 4 || j == y + 6)
                {
                    if (MAP[i][j] != 'W') Cnt++;
                }
                else
                {
                    if (MAP[i][j] != 'B') Cnt++;
                }
            }
            else
            {
                if (j == y || j == y + 2 || j == y + 4 || j == y + 6)
                {
                    if (MAP[i][j] != 'B') Cnt++;
                }
                else
                {
                    if (MAP[i][j] != 'W') Cnt++;
                }
            }
        }
    }
cs

   위의 코드는 왼쪽 위가 흰색일 때 체스판을 다시 칠해야 하는 갯수를 Count하는 코드이다.

  

   위의 코드를 제대로 이해했다면, 왼쪽 위가 검은색일 때 체스판을 다시 칠해야 하는 경우도 쉽게 해결할 수 있을 것이다.

   위의 부분을 모두 구현했다면, 이 후에 해야할 일은 뭐가 있을까??

   1. 왼쪽 위가 흰색일 때 최소인지 검은색일 때 최소인지 비교해서 최소값 찾기

   2. 그 최소값과 현재 전체 최소값을 비교해서 갱신해주기 !

  

[ 소스코드 ]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#include<iostream>
 
#define MAX 50
using namespace std;
 
int M, N;
char MAP[MAX][MAX];
 
int Min(int A, int B) { if (A < B) return A; return B; }
 
void Input()
{
    cin >> N >> M;
    for (int i = 0; i < N; i++)
    {
        for (int j = 0; j < M; j++)
        {
            cin >> MAP[i][j];
        }
    }
}
 
int Estimate_Num(int a)
{
    if (a % 2 == 0return 0;
    else return 1;
}
 
int Make_White_First(int x, int y)
{
    //x가 0일수도 잇고 1일수도 잇어
    //y도 0일수도 잇고 1일수도 잇어
    int Cnt = 0;
 
    for (int i = x; i < x + 8; i++)
    {
        for (int j = y; j < y + 8; j++)
        {
            if (i == x || i == x + 2 || i == x + 4 || i == x + 6)
            {
                if (j == y || j == y + 2 || j == y + 4 || j == y + 6)
                {
                    if (MAP[i][j] != 'W') Cnt++;
                }
                else
                {
                    if (MAP[i][j] != 'B') Cnt++;
                }
            }
            else
            {
                if (j == y || j == y + 2 || j == y + 4 || j == y + 6)
                {
                    if (MAP[i][j] != 'B') Cnt++;
                }
                else
                {
                    if (MAP[i][j] != 'W') Cnt++;
                }
            }
        }
    }
    return Cnt;
}
 
int Make_Black_First(int x, int y)
{
    int Cnt = 0;
 
    for (int i = x; i < x + 8; i++)
    {
        for (int j = y; j < y + 8; j++)
        {
            if (i == x || i == x + 2 || i == x + 4 || i == x + 6)
            {
                if (j == y || j == y + 2 || j == y + 4 || j == y + 6)
                {
                    if (MAP[i][j] != 'B') Cnt++;
                }
                else
                {
                    if (MAP[i][j] != 'W') Cnt++;
                }
            }
            else
            {
                if (j == y || j == y + 2 || j == y + 4 || j == y + 6)
                {
                    if (MAP[i][j] != 'W') Cnt++;
                }
                else
                {
                    if (MAP[i][j] != 'B') Cnt++;
                }
            }
        }
    }
    return Cnt;
}
 
void Make_Chess()
{
    int White_First_Min;
    int Black_First_Min;
    int Total_Min = 9999;
 
    for (int i = 0; i < N; i++)
    {
        if (i + 8 > N) break;
        for (int j = 0; j < M; j++)
        {
            if (j + 8 > M) break;
 
            White_First_Min = Make_White_First(i, j);
            Black_First_Min = Make_Black_First(i, j);
            Total_Min = Min(Total_Min, Min(White_First_Min, Black_First_Min));
        }
    }
    cout << Total_Min << endl;
}
 
void Solution()
{
    Make_Chess();
}
 
void Solve()
{
    Input();
    Solution();
}
 
int main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    //    freopen("Input.txt", "r", stdin);
    Solve();
 
    return 0;
}
cs











  

+ Recent posts