※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 14939번 문제인 불 끄기이다.
문제는 아래 링크를 확인하자.
https://www.acmicpc.net/problem/14939
14939번: 불 끄기
전구 100개가 10×10 정사각형 모양으로 늘어서 있다. 전구에 달린 스위치를 누르면 그 전구와 위, 아래, 왼쪽, 오른쪽에 있는 전구의 상태도 바뀐다. 전구 100개의 상태가 주어지면 모든 전구를 끄
www.acmicpc.net
첫 행의 전구를 건드리고, 앞으로 더 건드리지 않는 상황을 생각해보자. 이 때 첫 행의 전구를 모두 꺼진 상태로 만들려면 둘째 행을 통해 첫째 행을 건드리는 수밖에 없다. 또한 첫 행의 전구가 모두 꺼지게끔 두 번째 행의 전구를 건드리는 방법은 단 한가지만 나온다는 것을 관찰할 수 있다.
이러한 성질은 위 상황 이후 두번째 행과 세번째 행에 대해서도, 나아가 r번째 행과 r+1번째 행에 대해서도 반복적으로 나타나는 점을 관찰하자. 이를 이용하여 문제를 해결할 수 있다.
모든 첫 행의 전구를 건드리는 경우의 수(1024가지)에 대하여 위의 방식대로 전구를 건드려보고 그 결과 모든 전구가 꺼진다면 이 때의 시도횟수를 기록해 그 최솟값을 찾는 방식으로 문제를 해결하자.
각 행의 전구의 상태를 켜짐(1)과 꺼짐(0)으로, 즉 이진수로 비트마스킹하여 정수 하나로 나타내면 문제를 빠르게 해결할 수 있다.
아래는 제출한 소스코드이다.
#include <iostream>
#include <string>
using namespace std;
int count1(int x) {
int ret = 0;
while (x) {
if (x & 1) ret++;
x >>= 1;
}
return ret;
}
int board[11];
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
for (int i = 0; i < 10; i++) {
int& x = board[i];
string s; cin >> s;
for (auto& l : s) {
x <<= 1;
if (l == 'O') x++;
}
}
int ans = 1000000007;
for (int i = 0; i < 1024; i++) {
int cnt = count1(i);
int old = board[0], cur = board[1];
old ^= i;
old ^= (i << 1);
old ^= (i >> 1);
cur ^= i;
old &= 1023;
for (int r = 1; r < 10; r++) {
cnt += count1(old);
cur ^= old;
cur ^= (old << 1);
cur ^= (old >> 1);
cur &= 1023;
int tmp = old ^ board[r + 1];
old = cur;
cur = tmp;
}
if (old == 0) ans = min(ans, cnt);
}
if (ans < 1000000007) cout << ans;
else cout << -1;
}
'BOJ' 카테고리의 다른 글
[BOJ 14921 // C++] 용액 합성하기 (0) | 2022.04.24 |
---|---|
[BOJ 14922 // C++] 부분평균 (0) | 2022.04.24 |
[BOJ 24552 // C++] 올바른 괄호 (0) | 2022.04.22 |
[BOJ 24542 // C++] 튜터-튜티 관계의 수 (0) | 2022.04.21 |
[BOJ 24544 // C++] 카카오뷰 큐레이팅 효용성 분석 (0) | 2022.04.20 |