https://www.acmicpc.net/problem/14502
Solved
import sys
from itertools import combinations
from collections import deque
from copy import deepcopy
input = sys.stdin.readline
# 바이러스 전파 bfs
def bfs(arr):
dx, dy = (-1, 1, 0, 0), (0, 0, -1, 1)
for x in range(N):
for y in range(M):
if arr[x][y] == 2: # 바이러스인 경우
dq = deque([(x, y)])
while dq:
cx, cy = dq.popleft()
for i in range(4):
nx, ny = cx + dx[i], cy + dy[i]
if 0 <= nx < N and 0 <= ny < M and arr[nx][ny] == 0:
arr[nx][ny] = 2 # 바이러스 전파
dq.append((nx, ny))
return sum(row.count(0) for row in arr) # 안전 영역 계산
N, M = map(int, input().rstrip().split())
arr = [list(map(int, input().rstrip().split())) for _ in range(N)]
zero_idx = []
for i in range(N):
for j in range(M):
if arr[i][j] == 0:
zero_idx.append((i, j))
safe_max = 0
for walls in combinations(zero_idx, 3): # 3개의 벽 세우기
modified_arr = deepcopy(arr)
for x, y in walls:
modified_arr[x][y] = 1 # 벽 세우기
safe_max = max(safe_max, bfs(modified_arr)) # 안전 영역의 최댓값 갱신
print(safe_max)
문제에 대한 사고 흐름은 다음과 같았다.
zero_idx = []
for i in range(N):
for j in range(M):
if arr[i][j] == 0:
zero_idx.append((i, j))
다음과 같이 0의 좌표를 저장한다.
(리스트 컴프리헨션을 사용하는게 코드가 더 깔끔했겠지만!)
safe_max = 0
for walls in combinations(zero_idx, 3): # 3개의 벽 세우기
modified_arr = deepcopy(arr)
for x, y in walls:
modified_arr[x][y] = 1 # 벽 세우기
safe_max = max(safe_max, bfs(modified_arr)) # 안전 영역의 최댓값 갱신
다음 itertools의 combinations
을 사용해 zero_idx
로부터 3개의 벽을 세워줬다.
3개의 벽을 세우는 모든 방법에 대해 최대 안전 영역을 구해야하므로, deepcopy를 사용해 원본 배열을 복사해 사용했다.
combinations
로 뽑아낸 3개의 인덱스 값을 1로 채워준 뒤, bfs
함수의 arr
인자로 전달한다.
# 바이러스 전파 bfs
def bfs(arr):
dx, dy = (-1, 1, 0, 0), (0, 0, -1, 1)
for x in range(N):
for y in range(M):
if arr[x][y] == 2: # 바이러스인 경우
dq = deque([(x, y)])
while dq:
cx, cy = dq.popleft()
for i in range(4):
nx, ny = cx + dx[i], cy + dy[i]
if 0 <= nx < N and 0 <= ny < M and arr[nx][ny] == 0:
arr[nx][ny] = 2 # 바이러스 전파
dq.append((nx, ny))
return sum(row.count(0) for row in arr) # 안전 영역 계산
배열을 순회하며 2의 값을 가지는 인덱스의 x, y 좌표를 큐에 넣어준다.
이 때 통상적인 BFS와의 다른 점은, 방문했던 좌표에 다시 방문하면 안되는 제약이 없으므로 visited
배열 없이 사용한다.
바이러스의 전파가 완료되면 arr의 값을 2로 갱신해준 뒤, 큐에 있는 모든 좌표를 다 순회해 루프를 빠져나오면, 0의 값을 리턴해준다.
BFS와 브루트포스를 기반으로 생각할 거리가 많았던 문제지만, 접근하기는 수월한 편이었던 것 같다!
visited가 BFS에 무조건 필요한 것은 아니라는 점!