문제를 그림으로 간단히 설명하면 아래와 같다.
- 벽을 3개 세운다.
- DFS / BFS를 사용하여 바이러스를 퍼뜨린다.
- 바이러스가 퍼지지 않은 칸을 센다.
2번과 3번은 간단하게 구현할 수 있지만, 1번) 벽 3개의 위치 고르기
에서 벽 3개를 어떻게 골라야 할지 떠오르지 않아 다른 사람의 코드를 참고하였다.
처음에 '완전 탐색으로 그냥 해볼까?' 생각했지만, 경우의 수가 약 4만 개가 나오고 4만 개 모두를 DFS/BFS를 하면 안될 것 같았다. 🫠
벽 3개의 위치를 고르는 방법은 바로 ✨백트래킹✨이었다.
import sys
n, m = map(int, input().split()) # 세로, 가로
board = [[0 for _ in range(m)] for _ in range(n)]
for i in range(n):
board[i] = list(map(int, input().split()))
copy.deepcopy(board)
import copy
from collections import deque
def dfs():
stack = []
visited = []
temp = copy.deepcopy(board) # 깊은 복사
for i in range(n):
for j in range(m):
# 바이러스 시작점을 stack과 visited 배열에 담음
if temp[i][j] == 2 and (i, j) not in visited:
stack.append((i, j))
visited.append((i, j))
while stack:
# 1. 스택에서 원소를 pop한다.
cur = stack.pop()
dx = [-1, 0, 1, 0]
dy = [0, -1, 0, 1]
# 2. 인접 노드를 탐색
for i in range(4):
nx, ny = cur[0] + dx[i], cur[1] + dy[i]
# 3. 보드를 벗어난 경우, 이미 방문한 경우, 빈 칸(0)이 아닌 경우 continue
if nx<0 or nx>=n or ny<0 or ny>=m or (nx, ny) in visited or temp[nx][ny] != 0:
continue
# 4. 바이러스 전이
temp[nx][ny] = 2
# 5. 인접 노드를 스택에 넣고, 방문 처리
stack.append((nx, ny))
visited.append((nx, ny))
# 바이러스가 전이되지 않은 칸을 count
count = 0
for i in range(n):
for j in range(m):
if temp[i][j] == 0:
count += 1
global result
result = max(count, result)
def make_wall(count):
# 벽을 3개 설치했으면, bfs를 돌며 안전 영역의 크기를 계산
if count == 3:
bfs()
return
for i in range(n):
for j in range(m):
if board[i][j] == 0:
board[i][j] = 1
make_wall(count+1)
board[i][j] = 0
result = 0
make_wall(0)
print(result)
import sys
import copy
input = sys.stdin.readline
n, m = map(int, input().split()) # 세로, 가로
board = [[0 for _ in range(m)] for _ in range(n)]
for i in range(n):
board[i] = list(map(int, input().split()))
def dfs():
stack = []
visited = []
temp = copy.deepcopy(board)
for i in range(n):
for j in range(m):
if temp[i][j] == 2 and (i, j) not in visited:
stack.append((i, j))
visited.append((i, j))
while stack:
cur = stack.pop()
dx = [-1, 0, 1, 0]
dy = [0, -1, 0, 1]
for i in range(4):
nx, ny = cur[0] + dx[i], cur[1] + dy[i]
if nx<0 or nx>=n or ny<0 or ny>=m or (nx, ny) in visited or temp[nx][ny] != 0:
continue
temp[nx][ny] = 2
stack.append((nx, ny))
visited.append((nx, ny))
count = 0
for i in range(n):
for j in range(m):
if temp[i][j] == 0:
count += 1
global result
result = max(count, result)
def make_wall(count):
if count == 3:
dfs()
return
for i in range(n):
for j in range(m):
if board[i][j] == 0:
board[i][j] = 1
make_wall(count+1)
board[i][j] = 0
result = 0
make_wall(0)
print(result)
이미 방문한 경우 2로 만들지 않는다!
라는 조건이 필요가 없다.def dfs():
stack = []
temp = copy.deepcopy(board)
for i in range(n):
for j in range(m):
if temp[i][j] == 2:
stack.append((i, j))
while stack:
cur = stack.pop()
dx = [-1, 0, 1, 0]
dy = [0, -1, 0, 1]
for i in range(4):
nx, ny = cur[0] + dx[i], cur[1] + dy[i]
if nx<0 or nx>=n or ny<0 or ny>=m or temp[nx][ny] != 0:
continue
temp[nx][ny] = 2
stack.append((nx, ny))
count = 0
for i in range(n):
for j in range(m):
if temp[i][j] == 0:
count += 1
global result
result = max(count, result)