https://www.acmicpc.net/problem/14502
DFS
BFS
역시 삼성 기출이다. 전형적인 DFS, BFS 문제이고, 가로 세로 최대 길이가 8이라서 시간복잡도에 제한이 없어 문제 그대로 구현만 하면 된다.
그래프 탐색을 하면서 3곳에 벽을 세우고 바이러스를 확산시킨 다음에 안전 영역을 최대로 갱신 시켜주면 된다.
입력 받은 기본 배열은 변경되지 않게 하기 위해 deepcopy (내 풀이에서는 그냥 for문으로 직접 값을 옮겼다) 해서 사용하면 된다.
DFS 풀이
n, m = map(int, input().split())
# 0=빈 칸, 1=벽, 2=바이러스
graph = [list(map(int, input().split())) for _ in range(n)]
temp_graph = [[0 for _ in range(m)] for _ in range(n)]
dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]
# 바이러스 확산시키는 함수
def virus(x, y):
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
if 0 <= nx < n and 0 <= ny < m:
if temp_graph[nx][ny] == 0:
temp_graph[nx][ny] = 2
virus(nx, ny)
# 안전 영역의 크기 구하는 함수
def get_score():
cnt = 0
for x in range(n):
for y in range(m):
if temp_graph[x][y] == 0:
cnt += 1
return cnt
result = 0
def dfs(graph, cnt):
global result
if cnt == 3:
# 원래 배열 변경 막기 위해 deepcopy 방식으로 배열 값 옮기기
for i in range(n):
for j in range(m):
temp_graph[i][j] = graph[i][j]
for i in range(n):
for j in range(m):
# 바이러스가 있는 위치라면 확산시키기
if temp_graph[i][j] == 2:
virus(i, j)
# 안전 영역의 최대 크기 갱신
result = max(result, get_score())
return
for i in range(n):
for j in range(m):
# 빈 칸이면 벽 세워보기
if graph[i][j] == 0:
graph[i][j] = 1
dfs(graph, cnt+1)
graph[i][j] = 0
dfs(graph, 0)
print(result)
BFS 풀이
from collections import deque
n, m = map(int, input().split())
graph = [list(map(int, input().split())) for _ in range(n)]
temp = [[0 for _ in range(m)] for _ in range(n)]
dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]
# 바이러스 확산시키는 함수
def virus(x, y):
queue = deque()
queue.append((x, y))
while queue:
x, y = queue.popleft()
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
# 범위 내이고, 빈 칸이라면 바이러스 확산시키기
if 0 <= nx < n and 0 <= ny < m and temp[nx][ny] == 0:
temp[nx][ny] = 2
queue.append((nx, ny))
# 안전 영역의 크기 구하는 함수
def get_score():
cnt = 0
for i in range(n):
for j in range(m):
if temp[i][j] == 0:
cnt += 1
return cnt
result = 0
def make_wall(cnt):
global result
if cnt == 3:
for i in range(n):
for j in range(m):
# deepcopy 용도
temp[i][j] = graph[i][j]
for i in range(n):
for j in range(m):
# 바이러스가 있으면 확산시키기
if temp[i][j] == 2:
virus(i, j)
result = max(result, get_score())
return
for i in range(n):
for j in range(m):
# 빈 칸이면 벽 세워보기
if graph[i][j] == 0:
graph[i][j] = 1
make_wall(cnt + 1)
graph[i][j] = 0
make_wall(0)
print(result)
그래프 탐색 연습 겸 deepcopy, combinations 라이브러리를 사용하지 않고 직접 구현해 보았다.
다른 분의 코드를 구경하며, 라이브러리를 사용한 코드의 소요 시간을 봐봤는데 거의 5배 이상 빠르게 동작하더라... 어디선가 듣기로는 combinations를 사용하면 시간초과 날 확률이 높다고 들은 것 같은데 이 경우는 입력 데이터 범위가 큰 상황이었나 보다.
물론 그래프 탐색 연습삼아 직접 구현한 것이지만, 범위 작은 문제에서는 라이브러리를 사용하는게 좋을 것 같기도 하다. 파이썬의 엄청난 장점이기도 하니까!
(내 풀이는 아니지만...속도 비교를 봐보자면)
속도 비교 사진을 가져온 블로그를 참고로 걸어놓으려고 한다.