[백준] [파이썬] [구현] [BFS] 14502번: 연구소
- -
문제집 추천, 이 문제집에 나온 유형들만 공부해도 코딩테스트는 거뜬: https://www.acmicpc.net/workbook/by/BaaaaaaaaaaarkingDog
시간 제한: 2초
메모리 제한: 512MB
문제
인체에 치명적인 바이러스를 연구하던 연구소에서 바이러스가 유출되었다. 다행히 바이러스는 아직 퍼지지 않았고, 바이러스의 확산을 막기 위해서 연구소에 벽을 세우려고 한다.
연구소는 크기가 N×M인 직사각형으로 나타낼 수 있으며, 직사각형은 1×1 크기의 정사각형으로 나누어져 있다. 연구소는 빈 칸, 벽으로 이루어져 있으며, 벽은 칸 하나를 가득 차지한다.
일부 칸은 바이러스가 존재하며, 이 바이러스는 상하좌우로 인접한 빈 칸으로 모두 퍼져나갈 수 있다. 새로 세울 수 있는 벽의 개수는 3개이며, 꼭 3개를 세워야 한다.
벽을 3개 세운 뒤, 바이러스가 퍼질 수 없는 곳을 안전 영역이라고 한다.
즉, 벽을 3개 다 세우고 바이러스가 다 퍼진 이후, 0의 개수가 안전 영역의 크기이다.
연구소의 지도가 주어졌을 때 얻을 수 있는 안전 영역 크기의 최댓값을 구하는 프로그램을 작성하시오.
입력
첫째 줄에 지도의 세로 크기 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
오랜만에 맞춘 문제
구현문제로 글을 차근 차근 읽고 구현해야할 순서를 잘 잡으면 된다.
1. 벽을 세운다.
0인 구역에 벽 1을 3곳 세울 곳을 정해야 한다
2. 바이러스를 퍼트린다.
벽을 세우는 모든 경우의 수 마다 바이러스를 퍼트려야한다
3. 안전 영역, 즉, 0의 개수를 구해야한다.
그리고 각 경우의 수별 0의 개수를 구해 그중 최대값을 출력하면된다.
코드를 다 짜고 나서 시간이 꽤 걸리는걸로 보였는데 다행이 통과하였다.
내가 푼 코드
import sys
sys.stdin=open('input.txt', 'r')
from collections import deque
from itertools import combinations
import copy
moves = [(0,1), (1,0), (0,-1), (-1,0)]
def in_range(nx,ny):
return 0<=nx<N and 0<=ny<M
if __name__ == '__main__':
N,M=map(int, input().split())
original_board = [list(map(int, input().split())) for _ in range(N)]
check_board = copy.deepcopy(original_board)
visited = [[0 for _ in range(M)] for _ in range(N)]
idx = [(i,j) for i in range(N) for j in range(M)]
Q=deque()
res=0
# 1. 0 인곳들 중에 3곳 뽑아 벽 세우기
for a,b,c in list(combinations(idx,3)):
if all(original_board[e[0]][e[1]]==0 for e in [a,b,c]): # 뽑은 3곳이 모두 빈곳
for e in [a,b,c]:
check_board[e[0]][e[1]]=1 # 벽세우기
cnt=0
# 2. 바이러스 퍼트리기
for i in range(N):
for j in range(M):
if check_board[i][j]==2 and visited[i][j]==0:
Q.append((i,j))
visited[i][j]=1
while Q:
x,y=Q.popleft()
for dx,dy in moves:
nx=x+dx
ny=y+dy
if in_range(nx,ny) and check_board[nx][ny]==0 and visited[nx][ny]==0:
visited[nx][ny]=1
check_board[nx][ny]=2
Q.append((nx,ny))
# 3. 안전영역, 0의 개수 세기
for i in range(N):
for j in range(M):
if check_board[i][j]==0:
cnt+=1
res = max(res, cnt)
check_board = copy.deepcopy(original_board)
visited = [[0 for _ in range(M)] for _ in range(N)]
print(res)
combinations를 안쓰고 백트래킹으로 하는 법
import sys
sys.stdin=open('input.txt', 'r')
from collections import deque
from itertools import combinations
import copy
moves = [(0,1), (1,0), (0,-1), (-1,0)]
def in_range(nx,ny):
return 0<=nx<N and 0<=ny<M
def BFS():
global res
Q=deque()
check_board = copy.deepcopy(original_board)
visited = [[0 for _ in range(M)] for _ in range(N)]
cnt = 0
for i in range(N):
for j in range(M):
if check_board[i][j]==2 and visited[i][j]==0:
Q.append((i,j))
visited[i][j]=1
while Q:
x,y=Q.popleft()
for dx,dy in moves:
nx=x+dx
ny=y+dy
if in_range(nx,ny) and check_board[nx][ny]==0 and visited[nx][ny]==0:
visited[nx][ny]=1
check_board[nx][ny]=2
Q.append((nx,ny))
# 3. 안전영역, 0의 개수 세기
for i in range(N):
for j in range(M):
if check_board[i][j]==0:
cnt+=1
res = max(res, cnt)
def makeWall(cnt):
if cnt == 3:
BFS()
return
else:
for i in range(N):
for j in range(M):
if original_board[i][j]==0:
original_board[i][j]=1
makeWall(cnt+1)
original_board[i][j]=0
if __name__ == '__main__':
N,M=map(int, input().split())
original_board = [list(map(int, input().split())) for _ in range(N)]
visited = [[0 for _ in range(M)] for _ in range(N)]
idx = [(i,j) for i in range(N) for j in range(M)]
res=0
makeWall(0)
print(res)
'Computer Science > 코딩테스트 문제 풀이' 카테고리의 다른 글
[N시간만에 끝내는 Python 코딩테스트] 7편 : 2018 카카오 코딩테스트 6번 프렌즈4블록 (0) | 2023.12.25 |
---|---|
[N시간만에 끝내는 Python 코딩테스트] 6편 2018 카카오 코딩테스트 5번 뉴스 클러스터링 (0) | 2023.12.25 |
[N시간만에 끝내는 Python 코딩테스트] 5편 2018 카카오 코딩테스트 4번 셔틀버스 (0) | 2023.12.24 |
[N시간만에 끝내는 Python 코딩테스트] 4편 2018 카카오 코딩테스트 3번 캐시 (LRU) (0) | 2023.12.24 |
[N시간만에 끝내는 Python 코딩테스트] 3편 2018 카카오 코딩테스트 2번 다트게임 (with 정규표현) (0) | 2023.12.24 |
소중한 공감 감사합니다