비트마스킹 분류로 되어있는 문제이다.
처음 접근할때, 모든 스위치 상황을 비트마스킹으로 만들까 했는데, 10*10 맵을 비트마스킹으로 표시하면 이걸 담을 자료형이 마땅치 않아 접었다. 물론 여러개의 변수를 사용해서 만들 수는 있지만, 그렇게까지 해야할까... 싶었다.
문제가 속한 다른 분류에 그리디가 있어서 한번 생각을 꼬아봤다. 맨 윗줄만 탐색하고 나머지는 그때 그때 상황에따라 계산해보자...
첫 줄에 불을 켜냐 끄냐 경우의 수는 2^10이다. 따라서 그 경우의 수 만큼 탐색을 한다. 첫 줄의 상황에 맞게 스위치를 눌러놓고, 다음 줄 부터 마지막 줄 까지는 윗 줄 같은 열이 켜져있을 때 스위치를 누르는 선택을 한다. 이 때, toggle() 함수를 따로 만들어, temp[][]배열에 변경사항을 실행해준다.
이렇게 전부 순회하면서 스위치를 켜고 끈 다음, 마지막 줄이 전부 꺼져있는지 확인해 해당 조건이 가능한지 확인한다. 확인이 된 경우 스위치 횟수를 비교하며 최소값을 찾아 리턴하면 답이다!\
#include <iostream>
#include <climits>
int dy[] = {0, 0, 1, 0, -1};
int dx[] = {0, 1, 0, -1, 0};
char map[11][11];
char temp[11][11];
void sw_toggle(int n, int m)
{
for (int i = 0; i < 5; i++)
{
int ny = n + dy[i];
int nx = m + dx[i];
if (ny < 0 || ny >= 10 || nx < 0 || nx >= 10)
continue;
if (temp[ny][nx] == '#')
temp[ny][nx] = 'O';
else
temp[ny][nx] = '#';
}
}
int main()
{
std::cin.tie(0);
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
std::cin >> map[i][j];
}
int answer = INT_MAX;
for (int sw = 0; sw < (1 << 10); sw++) // 첫줄 스위치 경우의 수들
{
int cnt = 0;
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
temp[i][j] = map[i][j];
}
for (int i = 0; i < 10; i++)
{
if (sw & (1 << i))
{
cnt++;
sw_toggle(0, i); // 첫줄 스위치 순회하며 누르는 경우일때 누르기.
}
}
for (int i = 1; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (temp[i - 1][j] == 'O') // 윗줄 같은열이 켜져있을때
{
cnt++;
sw_toggle(i, j); // 끄기!
}
}
}
bool notAv = false;
for (int i = 0; i < 10; i++)
{
if (temp[9][i] == 'O') // 마지막 줄 켜져있으면
{
notAv = true; // 정답상황 아님
break;
}
}
if (!notAv)
answer = std::min(cnt, answer);
}
if (answer != INT_MAX)
std::cout << answer;
else
std::cout << -1;
}
모든 경우의 수를 비트마스킹으로 처리하려는 초기 접근이 좀 무리였던것 같다. 상황들에서 일부를 떼내어 파생 가능한지 고민을 해 보아야 겠다.
오늘도 평온한 하루가 되길. 슨민.
'짜잘한 기록' 카테고리의 다른 글
백준 15683 감시 (0) | 2021.11.03 |
---|---|
백준 15686 치킨 배달 (0) | 2021.11.01 |
백준 14391 종이 조각 (0) | 2021.10.26 |
백준 9328 열쇠 (0) | 2021.10.22 |
백준 1562 계단 수 (0) | 2021.10.21 |