www.acmicpc.net/problem/14939

 

14939번: 불 끄기

전구 100개가 10×10 정사각형 모양으로 늘어서 있다. 전구에 달린 스위치를 누르면 그 전구와 위, 아래, 왼쪽, 오른쪽에 있는 전구의 상태도 바뀐다. 전구 100개의 상태가 주어지면 모든 전구를 끄��

www.acmicpc.net


  • 같은 버튼이 두 번 이상 눌리지 않는다. 그 순간 최솟값이 될 수가 없다.
  • 모든 버튼이 한번씩만 눌린다고 했을 경우에는 각 버튼을 누르는 순서가 중요해지지 않는다.
  • 그렇게 되면 위에서부터 한 줄씩 차례대로 내려오면서 검사하면 된다.
  • 위에서부터 내려올 경우, 둘째 줄부터는 자신의 바로 윗줄의 상태에 따라서 누를지 말지 여부가 결정된다. 바로 윗칸의 버튼이 켜져 있는 상태라면 반드시 눌러서 꺼줘야 하고, 윗칸이 꺼져있으면 누르면 안되기 때문이다.
  • 나머지 줄들은 윗줄의 상태에 의해 자동 결정되므로, 첫 줄의 상태만 고려하면 된다.
  • 첫 줄에는 10칸이 있고, 각각 켜짐과 꺼짐의 상태가 있으므로 모든 경우의 수 1024 가지를 고려하여 계산하면 된다.

#include <iostream>

using namespace std;

int num = 1000;                 // 정답 넣어줄 변수, 이상치는 1000 으로 설정
bool state[10][10];             // 매번 검사해줄 용도의 배열
bool fixedState[10][10];        // 처음 입력받을 값들 고정 저장될 배열

void click(int row, int col)    // 해당 위치를 클릭했을 때 전구들의 상태를 바꿔줌
{
    state[row][col] = !state[row][col];
    if(row-1 >= 0) state[row-1][col] = !state[row-1][col];
    if(row+1 < 10) state[row+1][col] = !state[row+1][col];
    if(col-1 >= 0) state[row][col-1] = !state[row][col-1];
    if(col+1 < 10) state[row][col+1] = !state[row][col+1];
}

int check()                                         // state 배열이 유효한지, 유효하다면 클릭 수는 몇회인지 반환
{
    int temp = 0;
    for(int r = 1 ; r < 10 ; r++)                   // 첫 줄은 메인에서 처리됐으므로 두번째 줄부터 시작
    {
        for(int c = 0 ; c < 10 ; c++)
        {
            if(state[r-1][c])                       // 바로 윗 줄의 같은 칸의 전구가 켜져있는 상태면 무조건 눌러야 함
            {
                click(r, c);
                temp++;
            }
        }
    }
    for(int r = 0 ; r < 10 ; r++)                   // 쭉 검사했는데 켜져있는 전구가 있으면
    {
        for(int c = 0 ; c < 10 ; c++)
        {
            if(state[r][c] == true) return 1000;    // 불가능함, 1000 반환
        }
    }
    return temp;
}

int main(void)
{
    char temp;
    for(int r = 0 ; r < 10 ; r++)
    {
        for(int c = 0 ; c < 10 ; c++)
        {
            cin >> temp;
            if(temp == 'O') fixedState[r][c] = true;        // 처음에 정보 입력 받음
        }
    }
    for(int p = 0 ; p < 1024 ; p++)                         // 첫 줄 10개를 각각 킬지/끌지 에 대해서 모든 경우의 수 탐색
    {                                                       //  (2의 10승)
        for(int r = 0 ; r < 10 ; r++)
        {
            for(int c = 0 ; c < 10 ; c++)                   // 해당 반복문을 수행하기 위해 state 배열을 초기화
            {
                state[r][c] = fixedState[r][c];
            }
        }
        int ret = 0;
        for(int i = 0 ; i < 10 ; i++)                       // 비트마스킹을 통해 첫 줄 10개의 전구를 누를지 말지 판단
        {
            if(p & (1 << i))                                // 해당 전구를 눌러야 하는 위치라면
            {   
                ret++;                                      // 누름 처리
                click(0, i);
            }
        }
        ret += check();                                     // state 에 1024번 중 현재 반복(첫 줄 전구)의 상태 담겨있음
        if(ret < num) num = ret;                            // 최솟값 갱신
    }

    cout << (num == 1000 ? -1 : num) << '\n';               // 모든 경우의 수가 이상치 반환할 경우 불가능 -1 출력
}

'PS > BOJ' 카테고리의 다른 글

[백준] 14500.cpp : 테트로미노  (0) 2020.07.13
[백준] 17298.cpp : 오큰수  (0) 2020.07.12
[백준] 10026.cpp : 적록색약  (0) 2020.07.10
[백준] 9019.cpp : DSLR  (0) 2020.07.10
[백준] 1107.cpp : 리모컨  (0) 2020.07.09

+ Recent posts