1018. 체스판 다시 칠하기
그냥 브루트 포스 문제인데, 새삼 이런 알고리즘 문제는 발상을 잘 내야 한다는 것을 실감한 문제였다.
#include <iostream>
#include <algorithm>
#include <vector>
int main()
{
std::cin.tie(NULL);
int n, m, num, num1 = 0, num2 = 0, min;
std::cin >> n >> m;
min = n * m;
char c;
char chess[n][m];
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
std::cin >> c;
chess[i][j] = c;
}
}
for (int i = 0; i <= n - 8; i++)
{
for (int j = 0; j <= m - 8; j++)
{
for (int k = i; k < i + 8; k++)
{
//처음 색을 B로
for (int l = j; l < j + 8; l++)
{
if (k % 2 + l % 2 == 0 || k % 2 + l % 2 == 2)
{
if (chess[k][l] != 'B')
num1++;
}
else if (k % 2 + l % 2 == 1)
{
if (chess[k][l] != 'W')
num1++;
}
}
//처음 색을 W로
for (int l = j; l < j + 8; l++)
{
if (k % 2 + l % 2 == 0 || k % 2 + l % 2 == 2)
{
if (chess[k][l] != 'W')
num2++;
}
else if (k % 2 + l % 2 == 1)
{
if (chess[k][l] != 'B')
num2++;
}
}
}
num = num1 < num2 ? num1 : num2;
if (num < min) min = num;
num1 = 0; num2 = 0;
}
}
std::cout << min << '\n';
return 0;
}
문제에서 체스판의 크기를 8*8로 정해줬기 때문에 그 이상을 탐색할 필요가 없으므로 가장 바깥의 for문 2개는 주어진 체스판을 8*8 크기를 만족하는 범위에서 탐색하도록 했다. 여기까지는 괜찮았는데... 어떻게 체스판을 다시 칠할지를 탐색하는 거에서 편한 발상을 떠올리는게 어려웠었다.
사실 가장 큰 힌트는... 문제에 있었다. 문제를 보면 중간에 이렇게 적혀있다.
체스판은 검은색과 흰색이 번갈아서 칠해져 있어야 한다. 구체적으로, 각 칸이 검은색과 흰색 중 하나로 색칠되어 있고, 변을 공유하는 두 개의 사각형은 다른 색으로 칠해져 있어야 한다. 따라서 이 정의를 따르면 체스판을 색칠하는 경우는 두 가지뿐이다. 하나는 맨 왼쪽 위 칸이 흰색인 경우, 하나는 검은색인 경우이다.
체스판을 칠하는 경우는 두 가지라고 문제에서 친절하게(...) 알려줬다. '맨 왼쪽 위칸의 색을 어떤 색으로 정의하는가'만 정해져있으면 그 다음엔 어느 색이 와야하는지 판별하는 과정은 간단하다. 체스판을 배열로 나타냈을 때, 해당 배열의 위치 인덱스를 통해 흰 칸인지 검은 칸인지 알아내면 되는 것이다... 그러니 구현할 때도 맨 왼쪽 위칸을 검은색으로 정했을 경우, 흰색으로 정했을 경우 두 가지로 나누어 다시 칠해야 하는 정사각형의 최소 개수를 세고 비교하여 최소값을 결정한다.
저걸 알기 전까지는 그 전 칸의 색을 다른 변수에 기억하게 하여 비교하는 방법을 사용하려 했었는데, 이걸 보고는 너무나도 어이가 없도록 쉬워져서(ㅋㅋㅋㅋㅋ) 깜짝 놀랐다...
* 오늘의 교훈 : 문제를 잘 읽자! 규칙을 잘 찾아보자!
'공부 > 알고리즘' 카테고리의 다른 글
백트래킹 (1) | 2023.10.15 |
---|---|
[~0718] 알고리즘 (0) | 2021.07.19 |
[0626] 알고리즘 (0) | 2021.06.27 |
[0625] 알고리즘 (0) | 2021.06.26 |
[0624] 알고리즘 (0) | 2021.06.25 |