728x90
시간 제한 1초, 메모리 제한 256MB
# 조건
- 전구 100개가 10×10 정사각형 모양으로 늘어서 있다.
- 전구에 달린 스위치를 누르면 그 전구와 위, 아래, 왼쪽, 오른쪽에 있는 전구의 상태도 바뀐다.
- 전구 100개의 상태가 주어지면 모든 전구를 끄기 위해 최소한으로 눌러야 하는 스위치의 개수를 출력하라
# 접근 방법
브루트 포스와 그리디를 활용하여 비트마스킹으로 풀어줘야 하는 문제였다.. 비트마스킹으로 첫 줄의 모든 경우의 수를 구하는 아이디어가 잘 생각이 나지 않아 다른 블로그를 참고하였다.
https://bio-info.tistory.com/234핵심은 첫 행의 전구 10개에 대해 켜고 끄는 모든 경우의 수 2 ^ 10 = 1024개에 대하여, 두 번째 행부터는 윗 행의 전구가 켜져 있는 경우에만 스위치를 누르는 것이다.
처음에 전구 배열을 arr에 받고, 스위치를 눌릴 경우 편하게 바꿔주기 위하여 True와 False로 변경 해주었습니다.
이 때, 최중 출력 값으로 사용할 result를 101로 초기화하는데 이 이뉴는 스위치 개수가 최대 100개 여서 누른 스위치 개수의 최소값이 101이 될 수 없기 때문입니다.
스위치를 누르는 경우의 수를 0에서 1023까지 ck로 받은 후, deepcopy를 이용하여 처음 배열을 복사해줍니다.
- 여기서 1023를 이진수로 받는다면 모든 전구에 대해 켜지고 꺼지는 경우의 수까지 고려할 수 있기 때문입니다!
이후, 첫 행의 스위치를 누르는 경우를 k & (1<<j)로 반영해줍니다.
- 또한 첫 행의 스위치를 눌렀을 경우 주변 스위치에 대한 행동을 반영해줍니다.
2번째 행부터 바로 윗 행의 스위치가 켜져있다면 스위치를 눌리면서 cnt를 + 해줍니다.
- 이후 10번째 행에 모든 전구의 불이 꺼져있다면 최소값을 비교하여 갱신해주면 됩니다.
import sys
sys.stdin = open('input.txt')
input = sys.stdin.readline
from copy import deepcopy
di, dj = [-1, 1, 0, 0, 0], [0, 0, 0, -1, 1]
result = 101
arr = [[False] * 10 for _ in range(10)]
for i in range(10):
a = input()
for j in range(10):
if a[j] == 'O':
arr[i][j] = True
# 첫 줄의 모든 경우의 수
for ck in range(1 << 10):
new_arr = deepcopy(arr)
cnt = 0
# 첫줄에 10개 전구 하나씩 탐색
for k in range(10):
# j번째 스위치를 누른다면 +1
if ck & (1 << k):
cnt += 1
# 맨윗줄 방향 살피기
for d in range(5):
ni, nj = 0+di[d], k + dj[d]
if 0<=ni<=9 and 0 <= nj <= 9:
new_arr[ni][nj] = not new_arr[ni][nj]
for i in range(1,10):
for j in range(10):
if new_arr[i-1][j] == True:
cnt += 1
for d in range(5):
ni, nj = i + di[d], j + dj[d]
if 0 <= ni <= 9 and 0 <= nj <= 9:
new_arr[ni][nj] = not new_arr[ni][nj]
if all(c == False for c in new_arr[-1]):
result = min(result, cnt)
print(result if result < 101 else -1)
728x90
'ALGORITHM > Greedy' 카테고리의 다른 글
[프로그래머스] 파이썬 - 점 찍기 (0) | 2023.05.23 |
---|---|
[프로그래머스] 파이썬 - 택배 배달과 수거하기 (0) | 2023.05.22 |
[백준 1450번] C++ - 걷기 (0) | 2023.05.03 |
[백준 19941번] C++ - 햄버거 분배 (0) | 2023.05.01 |
[백준 10775번] 파이썬 - 공항 (0) | 2023.04.18 |