연구소
https://www.acmicpc.net/workbook/view/1152
문제
인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다.
연구소는 크기가 N×M인 직사각형으로 나타낼 수 있으며, 직사각형은 1×1 크기의 정사각형으로 나누어져 있다. 연구소는 빈 칸, 벽으로 이루어져 있으며, 벽은 칸 하나를 가득 차지한다.
일부 칸은 바이러스가 존재하며, 이 바이러스는 상하좌우로 인접한 빈 칸으로 모두 퍼져나갈 수 있다. 새로 세울 수 있는 벽의 개수는 3개이며, 꼭 3개를 세워야 한다.
-중략-
입력
첫째 줄에 지도의 세로 크기 N과 가로 크기 M이 주어진다. (3 ≤ N, M ≤ 8)
둘째 줄부터 N개의 줄에 지도의 모양이 주어진다. 0은 빈 칸, 1은 벽, 2는 바이러스가 있는 위치이다. 2의 개수는 2보다 크거나 같고, 10보다 작거나 같은 자연수이다.
빈 칸의 개수는 3개 이상이다.
출력
첫째 줄에 얻을 수 있는 안전 영역의 최대 크기를 출력한다.
예제 입력
7 7
2 0 0 0 1 1 0
0 0 1 0 1 2 0
0 1 1 0 1 0 0
0 1 0 0 0 0 0
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 1 0 0 0 0 0
예제 출력
27
풀이
벽은 총 3개를 세울 수 있다. 0으로 표시된 곳에 3개를 골라서 세울 수 있으므로 조합문제
이다. 벽 3개를 세울 때마다 바이러스를 퍼뜨리면 된다. 바이러스를 퍼뜨리는 방식은 queue
나 stack
을 이용하면 된다. 바이러스로 오염된 공간을 꺼내와서 (queue pop이나 stack pop) 인접한 4개의 방향을 바이러스 감염으로 표시하고 stack이나 queue에 다시 넣으면 된다. DFS나 BFS의 개념으로 생각하면 된다. (무엇을 사용해도 상관없다.)
- 빈 공간 3개를 선택해서 벽을 세운다.
- 2로 표시된 바이러스를 모두 stack에 넣고 pop하면서 4방으로 퍼뜨린다. (벽이나 경계를 만나면 추가하지 않는다.)
- stack이 비어있을 때까지 계속한다.
- 다른 빈공간 3개를 선택해서 위를 반복한다.
from sys import stdin
import copy
N, M = list(map(int, stdin.readline().split()))
board = []
for n in range(N):
board.append(list(map(int, stdin.readline().split())))
# virus
# build walls -> spread virus -> init
# stack
def spreadVirus(walls, board):
virus = list()
result = 0
tmp_board = copy.deepcopy(board)
# build walls
for wall in walls:
tmp_board[wall[0]][wall[1]] = 1
for n in range(N):
for m in range(M):
if tmp_board[n][m] == 2:
virus.append([n, m])
move = [[1, 0], [-1, 0], [0, 1], [0, -1]]
# spread virus
while virus:
now = virus.pop()
for m in move:
spread_y = now[0] + m[0]
spread_x = now[1] + m[1]
if spread_y <= N-1 and spread_y >= 0 and spread_x <= M-1 and spread_x >= 0 and tmp_board[spread_y][spread_x] == 0:
tmp_board[spread_y][spread_x] = 2
virus.append([spread_y, spread_x])
for n in range(N):
for m in range(M):
if tmp_board[n][m] == 0:
result += 1
global MAX
if result > MAX:
MAX = result
return 0
# combination
# recursive
chosen = []
MAX = 0
def recur(nxt_y, nxt_x):
if len(chosen) == 3:
spreadVirus(chosen, board)
return
for y in range(nxt_y, N):
for x in range(nxt_x, M):
if board[y][x] == 0:
chosen.append([y, x])
recur(y, x+1)
chosen.pop()
nxt_x = 0
recur(0, 0)
print(MAX)