Algorithm(BOJ, Python)/BFS&DFS

[백준_7569] 토마토 python

kurooru 2022. 8. 22. 11:28

3차원 배열만 잘 구현할 수 있다면,

어렵지 않게 해결할 수 있는 문제였다.

# m, n, h 입력
m, n, h = map(int, input().split())

# storage 설계
storage = []

# 각 층 입력
for _ in range(h):
    floor = [
        list(map(int, input().split()))
        for _ in range(n)
    ]
    storage.append(floor)

# 함수들

# in_range(f, x, y)
def in_range(f, x, y):
    return 0 <= f and f < h and 0 <= x and x < n and 0 <= y and y < m

# check(f, x, y)
def check(f, x, y):
    # 범위 안에 있고, 안익은 토마토여야 하고, 방문한 적 없어야 함
    return in_range(f, x, y) and storage[f][x][y] == 0 and not visited[f][x][y]

# bfs()
def bfs():
    while q:
        f, x, y = q.popleft()
        
        # dfs, dxs, dys
        dfs, dxs, dys = [0, 0, 0, 0, -1, 1], [-1, 1, 0, 0, 0, 0], [0, 0, -1, 1, 0, 0]

        for df, dx, dy in zip(dfs, dxs, dys):
            # 조사 위치
            nf, nx, ny = f + df, x + dx, y + dy
            # 조사 위치가 익을 수 있는 위치면
            if check(nf, nx, ny):
                # 방문 표시 해 주고,
                visited[nf][nx][ny] = 1
                # step 배열 올려주고
                step[nf][nx][ny] = step[f][x][y] + 1
                # 큐에 넣어주기
                q.append((nf, nx, ny))

# blocked()
def blocked():
    # storage와 visited를 동시에 돌면서
    for f in range(h):
        for i in range(n):
            for j in range(m):
                # storage가 0인데(익지 않은 토마토가 있는데),
                # visited가 0인 토마토가 있으면,
                if storage[f][i][j] == 0 and not visited[f][i][j]:
                    # 막힌거임
                    return True
    # 다 돌았는데 그런 토마토가 없으면,
    # 안막힌거임
    return False

# all_done()
def all_done():
    # storage 돌면서
    for f in range(h):
        for i in range(n):
            for j in range(m):
                # 안익은 토마토가 있으면
                if storage[f][i][j] == 0:
                    # 실패
                    return False
    # 없으면 성공
    return True

# 설계
# 큐 사용 준비
from collections import deque
q = deque()

# 모든 토마토가 익어있는 상태인지 확인
if all_done():
    print(0)

# 아니라면,
else:
    
    # visited
    visited = [[[0 for _ in range(m)] for _ in range(n)] for _ in range(h)]

    # step
    step = [[[0 for _ in range(m)] for _ in range(n)] for _ in range(h)]

    # storage를 돌면서
    for f in range(h):
        for i in range(n):
            for j in range(m):
                # 익은 토마토를 만나면,
                if storage[f][i][j] == 1:
                    # 큐에 좌표를 넣어주고
                    q.append((f, i, j))
                    # 방문 처리 해줌
                    visited[f][i][j] = 1
    
    # 모든 좌표를 넣어주었으면,
    # bfs 돌려줌
    bfs()

    # 만약 bfs 돌린 후에 익지 못한 곳이 있다면,
    if blocked():
        print(-1)
    
    # 다 익었다면,
    else:

        # 최댓값 설정
        import sys
        max_step = -sys.maxsize

        # step 돌면서
        for f in range(h):
            for i in range(n):
                for j in range(m):
                    # 값이 현재 최댓값보다 크다면
                    if step[f][i][j] > max_step:
                        # 최댓값 갱신
                        max_step = step[f][i][j]
        
        # 출력
        print(max_step)