본문 바로가기

Problem Solving/Baekjoon Online Judge

< BFS > 7576번 토마토 with 파이썬

 

문제

 철수의 토마토 농장에서는 토마토를 보관하는 큰 창고를 가지고 있다. 토마토는 아래의 그림과 같이 격자 모양 상자의 칸에 하나씩 넣어서 창고에 보관한다.

 창고에 보관되는 토마토들 중에는 잘 익은 것도 있지만, 아직 익지 않은 토마토들도 있을 수 있다. 보관 후 하루가 지나면, 익은 토마토들의 인접한 곳에 있는 익지 않은 토마토들은 익은 토마토의 영향을 받아 익게 된다. 하나의 토마토의 인접한 곳은 왼쪽, 오른쪽, 앞, 뒤 네 방향에 있는 토마토를 의미한다. 대각선 방향에 있는 토마토들에게는 영향을 주지 못하며, 토마토가 혼자 저절로 익는 경우는 없다고 가정한다. 철수는 창고에 보관된 토마토들이 며칠이 지나면 다 익게 되는지, 그 최소 일수를 알고 싶어 한다.

 

 토마토를 창고에 보관하는 격자모양의 상자들의 크기와 익은 토마토들과 익지 않은 토마토들의 정보가 주어졌을 때, 며칠이 지나면 토마토들이 모두 익는지, 그 최소 일수를 구하는 프로그램을 작성하라. 단, 상자의 일부 칸에는 토마토가 들어있지 않을 수도 있다.

입력

 첫 줄에는 상자의 크기를 나타내는 두 정수 M,N이 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M,N ≤ 1,000 이다. 둘째 줄부터는 하나의 상자에 저장된 토마토들의 정보가 주어진다. 즉, 둘째 줄부터 N개의 줄에는 상자에 담긴 토마토의 정보가 주어진다. 하나의 줄에는 상자 가로줄에 들어있는 토마토의 상태가 M개의 정수로 주어진다. 정수 1은 익은 토마토, 정수 0은 익지 않은 토마토, 정수 -1은 토마토가 들어있지 않은 칸을 나타낸다.

토마토가 하나 이상 있는 경우만 입력으로 주어진다.

출력

 여러분은 토마토가 모두 익을 때까지의 최소 날짜를 출력해야 한다. 만약, 저장될 때부터 모든 토마토가 익어있는 상태이면 0을 출력해야 하고, 토마토가 모두 익지는 못하는 상황이면 -1을 출력해야 한다.

정답비율

 33.411%

알고리즘 분류

 #그래프 #그래프탐색 #탐색 #BFS #너비우선탐색

 

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

def bfs(queue):
    dx = [-1, 0, 1, 0]
    dy = [0, 1, 0, -1]
    while queue:
        x, y, d = queue.popleft()
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if nx < 0 or nx >= n or ny < 0 or ny >= m  :
                continue
            if graph[nx][ny] == -1 :
                continue
            else :
                if graph[nx][ny] == 0:
                    graph[nx][ny] = d + 1
                    queue.append((nx, ny, d + 1))

global m, n, graph, day
m, n = map(int, input().split())
graph = []
queue = deque()
for _ in range(n):
    graph.append(list(map(int, input().split())))

for i in range(n):
    for j in range(m):
        if graph[i][j] == 1:
            queue.append((i, j, 1))
bfs(queue)

answer = 0
for i in range(n):
    for j in range(m):
        if graph[i][j] == 0:
            print(-1)
            quit()
        answer = max(answer, graph[i][j])

print(answer-1)

 

 - 두 번이나 시간초과가 났던 문제이다. bfs를 제대로 활용하지 못했던 내 실수이다.

 

 - 위 코드를 살펴보면 그래프를 만들고 1이 있으면 모두 큐에 넣어 주었다. 세 번째 인자로는 day를 넣어주었다.

 

 - 1부터 넣은이유는 기존 값인 1과 구분하기 위해서이다. 주변이 0일경우 마다 방문표시를 d + 1로 하였고, 큐에 위치좌표와 d + 1 된 day값을 넣어주었다.

 

 - bfs의 장점은 마치 동시에 이루어지는 것처럼 할 수 있다는 것인데, 처음에 큐에 1인 값을 여러 개 담았고, 그들 모두가 동시에 주변의 숫자를 늘리는 것처럼 하게 된다.

 

 - 결과적으로 얻은 그래프를 탐색하여 최대 day값을 구하고 -1을 하여 답을 출력하였다.

 

 - 만약 탐색하다가 0을 발견하면 익지 못한 토마토가 있는 것이므로 -1을 출력하고 프로그램을 종료시켰다.

 

 - 처음에 시간초과가 났던 이유는 1을 발견할 때마다 bfs를 돌렸기 때문이다. 그렇게 한 후 조건에 day가 현재 day+1 보다 크면 재방문하며 숫자를 조정했다.

 

 - 답은 같게 나왔지만 어마어마한 히든케이스들이 숨겨져있는 것 같았다. 답안확인 시간이 얼마나 길었는지 모른다. 아무래도 재방문이라는 것 자체를 하지 않도록 해야되는 것 같다. 처음에 bfs를 제대로 활용못한 것이다.

 

 


 

 

참고

 

7576번: 토마토

첫 줄에는 상자의 크기를 나타내는 두 정수 M,N이 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M,N ≤ 1,000 이다. 둘째 줄부터는 하나의 상자에 저장된 토마토

www.acmicpc.net