[BOJ: 14502] - Python / 파이썬 - 연구소

o_jooon_·2024년 1월 14일
0

BOJ

목록 보기
4/49
post-thumbnail

서론

구현, 브루트포스, bfs 문제입니다.
확산하는 과정 자체는 bfs로 쉽게 구현이 가능한 문제입니다만 벽을 세우는 과정을 조금 고민해야 합니다.
이전에 포스팅 했던 문제(치킨 배달)와 같이 3개의 임의의 값을 선택하는 문제였습니다.(이게 더 어렵지만)
그렇기에 조합보다 더 빠른 시간복잡도를 가진 백트래킹으로 구현하였습니다.
처음 작성했던 코드 그대로 통과하여 기분이 좋네요.
다른 분들의 풀이를 보면 백트래킹 안쓰고 빠르게 통과하신 분들이 있던데 머리 아파서 포기^^

난이도

골드 4


문제

조건

인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다.

연구소는 크기가 N×M인 직사각형으로 나타낼 수 있으며, 직사각형은 1×1 크기의 정사각형으로 나누어져 있다. 연구소는 빈 칸, 벽으로 이루어져 있으며, 벽은 칸 하나를 가득 차지한다.

일부 칸은 바이러스가 존재하며, 이 바이러스는 상하좌우로 인접한 빈 칸으로 모두 퍼져나갈 수 있다. 새로 세울 수 있는 벽의 개수는 3개이며, 꼭 3개를 세워야 한다.

예를 들어, 아래와 같이 연구소가 생긴 경우를 살펴보자.

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

이때, 0은 빈 칸, 1은 벽, 2는 바이러스가 있는 곳이다. 아무런 벽을 세우지 않는다면, 바이러스는 모든 빈 칸으로 퍼져나갈 수 있다.

2행 1열, 1행 2열, 4행 6열에 벽을 세운다면 지도의 모양은 아래와 같아지게 된다.

2 1 0 0 1 1 0
1 0 1 0 1 2 0
0 1 1 0 1 0 0
0 1 0 0 0 1 0
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 1 0 0 0 0 0

바이러스가 퍼진 뒤의 모습은 아래와 같아진다.

2 1 0 0 1 1 2
1 0 1 0 1 2 2
0 1 1 0 1 2 2
0 1 0 0 0 1 2
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 1 0 0 0 0 0

벽을 3개 세운 뒤, 바이러스가 퍼질 수 없는 곳을 안전 영역이라고 한다. 위의 지도에서 안전 영역의 크기는 27이다.

연구소의 지도가 주어졌을 때 얻을 수 있는 안전 영역 크기의 최댓값을 구하는 프로그램을 작성하시오.

입력

첫째 줄에 지도의 세로 크기 N과 가로 크기 M이 주어진다. (3 ≤ N, M ≤ 8)

둘째 줄부터 N개의 줄에 지도의 모양이 주어진다. 0은 빈 칸, 1은 벽, 2는 바이러스가 있는 위치이다. 2의 개수는 2보다 크거나 같고, 10보다 작거나 같은 자연수이다.

빈 칸의 개수는 3개 이상이다.

출력

첫째 줄에 얻을 수 있는 안전 영역의 최대 크기를 출력한다.

예시

예제 입력 1

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

예제 출력 1

27

예제 입력 2

4 6
0 0 0 0 0 0
1 0 0 0 0 2
1 1 1 0 0 2
0 0 0 0 0 2

예제 출력 2

9

풀이

  1. 입력 배열에서 바이러스 위치와 안전 영역 위치 저장
  2. 백트래킹을 이용하여 안전 영역 3개를 임의로 선택
  3. 3개의 안전 영역이 선택되면 copy를 이용하여 입력 배열 복사 후 선택된 영역들 벽으로 변경
    (3개가 선택될 때마다 입력 배열에서 임의의 영역 3개를 벽으로 바꿔야 하기 때문에 copy 사용)
  4. 복사된 배열을 bfs를 통해 바이러스 확산
  5. 확산 후 안전 영역의 수를 카운트하여 모든 경우의 수 중 가장 높은 수 출력

코드

import sys, copy
from collections import deque
input = sys.stdin.readline

def spread(new_board):	# 바이러스 확산(bfs)
    q = deque(virus)	# bfs를 위해 바이러스의 위치를 deque으로 변경
    cnt = 0				# 안전 영역의 수를 카운트하기 위한 변수

    while q:			
        x, y = q.popleft()

        for dx, dy in dxy:
            nx, ny = x + dx, y + dy
            if 0 <= nx < n and 0 <= ny < m and new_board[nx][ny] == 0:
                new_board[nx][ny] = 2	# 안전 영역만 바이러스 확산
                q.append((nx, ny))
    
    for i in range(n):
        for j in range(m):
            if new_board[i][j] == 0:
                cnt += 1	# 확산 후 남은 안전영역 카운트

    return cnt

def dfs(depth, idx):	# 백트래킹
    global ans
    if depth == 3:							# 안전 영역 중 3개가 임의로 선택되면
        new_board = copy.deepcopy(board)	# 초기 배열을 복사한 새로운 배열 생성
        for x, y in wall:
            new_board[x][y] = 1				# 복사된 배열에 3개의 벽 설치

        ans = max(ans, spread(new_board))	# 바이러스 확산 후 안전 영역 최대치 찾기
        return

    for i in range(idx, len(safe_area)):
        wall.append(safe_area[i])
        dfs(depth + 1, i + 1)
        wall.pop()

n, m = map(int, input().split())
board = [list(map(int, input().split())) for _ in range(n)]
dxy = [(0, 1), (0, -1), (1, 0), (-1, 0)]
safe_area = []
virus = []
wall = []
ans = 0

for x in range(n):
    for y in range(m):
        if board[x][y] == 0:
            safe_area.append((x, y))
        elif board[x][y] == 2:
            virus.append((x, y))

dfs(0, 0)
print(ans)

실행 결과

profile
안녕하세요.

0개의 댓글