[백준]-토마토

이정연·2022년 10월 14일
0

CodingTest

목록 보기
11/165

토마토

solved_ac[Class3][토마토](https://www.acmicpc.net/problem/7576)

문제

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

img

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

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

입력

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

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

출력

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

  • 예제 입력 1
6 4
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 1
  • 예제 출력 1
8
  • 예제 입력 2
6 4
0 -1 0 0 0 0
-1 0 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 1
  • 예제 출력 2
-1
  • 예제 입력 3
6 4
1 -1 0 0 0 0
0 -1 0 0 0 0
0 0 0 0 -1 0
0 0 0 0 -1 1
  • 예제 출력 3
6
  • 예제 입력 4
5 5
-1 1 0 0 0
0 -1 -1 -1 0
0 -1 -1 -1 0
0 -1 -1 -1 0
0 0 0 0 0
  • 예제 출력 4
14
  • 예제 입력 5
2 2
1 -1
-1 1
  • 예제 출력 5
0

BFS

이 문제는 DFS로 풀면 안 되고 BFS로만 풀어야 한다. 그 이유에 대한 설명으로 다음 그림을 참조해보자.

스크린샷 2022-05-19 오전 8 06 53

진행 순서를 나타낸 그림이다. 이 문제에서의 포인트는 토마토가 동시에 익어간다는 점이다. 따라서 값이 1인 노드들에서 단계별로 진행을 해야 최소 익힘 일수를 구할 수 있다.

만일, DFS로 진행할 경우 (1,0)의 토마토는 (0,0) 토마토에 의해 1일 만에 익을 수 있는 건데 "깊이 우선"이라는 특성 때문에 (3,5) 토마토에 의하여 12일 만에 익게 된다는 이상한 결과가 도출된다.

구현 애로사항

그래프 탐색 문제는 항상 구현이 어렵다. 이 문제에서 어려웠던 부분은 토마토가 동시에 익어간다는 점이었다.

처음에는 그림과 같이 기본 베이직 BFS 함수에 day 변수만 추가시켜 while문이 끝날 때마다 +1씩 증가시켜주려 했었다. 그러나 그렇게 하면 day가 중첩되어 증가하는 문제가 생긴다.

스크린샷 2022-05-19 오전 8 24 06

결국 "Numbering"기법을 통하여 Value를 저장시키는 방법의 힌트를 얻었고 이를 통하여 문제를 풀었다.

비슷한 문제 치즈가 있었는데 이 때 얻었던 아이디어를 까먹고 있었다.

CODE

import sys
from collections import deque
input = sys.stdin.readline
INF = int(1e9)
# 초기 조건
m,n = map(int,input().split())
tomato = [list(map(int,input().split())) for _ in range(n)]

q = deque()
# stack = []
for i in range(n):
    for j in range(m):
        if tomato[i][j] == 1:
            q.append((i,j))
            stack.append((i,j))

dx = [1,-1,0,0]
dy = [0,0,1,-1]

def bfs(tomato):
    while q:
        i,j = q.popleft()

        for k in range(4):
            x = i+dx[k]
            y = j+dy[k]
        
            if 0<=x<n and 0<=y<m and tomato[x][y] == 0:
                tomato[x][y] = tomato[i][j] + 1
                q.append((x,y))

# def dfs(tomato):
#     while stack:
#         i,j = stack.pop()

#         for k in range(4):
#             x = i+dx[k]
#             y = j+dy[k]

#             if 0<=x<n and 0<=y<m and tomato[x][y] == 0:
#                 tomato[x][y] = tomato[i][j] + 1
#                 stack.append((x,y))

def check_zero(tomato):
    for i in tomato:
        if 0 in i:
            return True
    return False

def check_day(tomato):
    day = -1*INF

    for i in tomato:
        day = max(max(i),day)
    return day


bfs(tomato)


if check_zero(tomato):
    print(-1)
else:
    print(check_day(tomato)-1)

규칙 설명

  • 최초의 1을 큐에 넣는다.
  • 상하좌우 탐색을 하여 0이면 (이전값 +1)로 업데이트
  • 그렇게 BFS를 끝마쳤을 때 예시 결과는 첫 번째 그림과 같다.

  • Case1. 만일 토마토 배열에 0이 1개라도 존재하는 경우: -1 벽에 가로막혀 익지 않는다. --> -1 출력
  • Case2. (배열의 최대값 - 1)이 모든 토마토가 익는 최소 일수이다.
profile
0x68656C6C6F21

0개의 댓글