[백준/BOJ][Python] 6593번 상범 빌딩

Eunding·2024년 2월 13일
0

algorithm

목록 보기
81/107

6593번 상범 빌딩

https://www.acmicpc.net/problem/6593

문제

당신은 상범 빌딩에 갇히고 말았다. 여기서 탈출하는 가장 빠른 길은 무엇일까? 상범 빌딩은 각 변의 길이가 1인 정육면체(단위 정육면체)로 이루어져있다. 각 정육면체는 금으로 이루어져 있어 지나갈 수 없거나, 비어있어서 지나갈 수 있게 되어있다. 당신은 각 칸에서 인접한 6개의 칸(동,서,남,북,상,하)으로 1분의 시간을 들여 이동할 수 있다. 즉, 대각선으로 이동하는 것은 불가능하다. 그리고 상범 빌딩의 바깥면도 모두 금으로 막혀있어 출구를 통해서만 탈출할 수 있다.

당신은 상범 빌딩을 탈출할 수 있을까? 만약 그렇다면 얼마나 걸릴까?

입력

입력은 여러 개의 테스트 케이스로 이루어지며, 각 테스트 케이스는 세 개의 정수 L, R, C로 시작한다. L(1 ≤ L ≤ 30)은 상범 빌딩의 층 수이다. R(1 ≤ R ≤ 30)과 C(1 ≤ C ≤ 30)는 상범 빌딩의 한 층의 행과 열의 개수를 나타낸다.

그 다음 각 줄이 C개의 문자로 이루어진 R개의 행이 L번 주어진다. 각 문자는 상범 빌딩의 한 칸을 나타낸다. 금으로 막혀있어 지나갈 수 없는 칸은 '#'으로 표현되고, 비어있는 칸은 '.'으로 표현된다. 당신의 시작 지점은 'S'로 표현되고, 탈출할 수 있는 출구는 'E'로 표현된다. 각 층 사이에는 빈 줄이 있으며, 입력의 끝은 L, R, C가 모두 0으로 표현된다. 시작 지점과 출구는 항상 하나만 있다.

출력

각 빌딩에 대해 한 줄씩 답을 출력한다. 만약 당신이 탈출할 수 있다면 다음과 같이 출력한다.

Escaped in x minute(s).
여기서 x는 상범 빌딩을 탈출하는 데에 필요한 최단 시간이다.

만일 탈출이 불가능하다면, 다음과 같이 출력한다.

Trapped!

예제 입력 1

3 4 5
S....
.###.
.##..
###.#

##.##
##...

#.###
####E

1 3 3
S##
#E#

0 0 0

예제 출력 1

Escaped in 11 minute(s).
Trapped!


풀이

7569번 토마토 문제와 로직이 거의 비슷한 문제였다.

  1. 3차원 리스트 입력받기
  2. 시작 지점 찾기
  3. 시작 지점을 기준으로 x축, y축, z축을 BFS로 탐색하면서 거리 재기
  4. 'E' 지점 만나면 종료

이 로직대로 진행하면 된다!
(개인적으로 문제는 어렵지 않았는데 3차원 입력 받을 때 층마다 공백이 있어서 막혔었다..)

3차원 리스트 입력받기

 	board = []
    for _ in range(L):
        board.append([list(input().strip()) for _ in range(R)])
        input()
  • 이렇게 층마다 공백은 input()으로 날려버리면 간단하다.
  • input().strip()을 쓴 이유는 strip()을 안쓰면 맨 뒤에 '\n'도 들어가는데 이 개행문자열을 빼기 위해서이다.

시작 지점 찾기

def findStart():
    for i in range(L):
        for j in range(R):
            for k in range(C):
                if board[i][j][k] == 'S':
                    board[i][j][k] = 0
                    return i, j, k
  • 시작 지점 찾는 걸 함수로 구현한 이유는 'S'를 발견했을 때 break 쓰면 제일 안쪽 for문만 종료되고 또 flag 변수 써서 종료 쓰는 게 너무 귀찮아서 'S'찾으면 return으로 종료시켜주기 위해서이다.
  • 이때 시작지점을 0으로 한 이유는 0부터 퍼져나가면서 1씩 증가시킬 예정

BFS 구현

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

def bfs():
    while queue:
        z, x, y = queue.popleft()
        for i in range(6):
            nz = z + dz[i]
            nx = x + dx[i]
            ny = y + dy[i]
            # 범위 체크
            if 0 <= nz and nz < L and 0 <= nx and nx < R and 0 <= ny and ny < C:
                if board[nz][nx][ny] == '.':
                    board[nz][nx][ny] = board[z][x][y] + 1
                    queue.append((nz, nx, ny))

                elif board[nz][nx][ny] == 'E':
                    return "Escaped in %d minute(s)." % (board[z][x][y] + 1)

    return "Trapped!"
  • 상하좌우+위층+아래층까지 총 6방향으로 퍼져나갈 수 있고 이에 따라서 dz, dx, dy 리스트도 미리 정의

  • 탐색할 위치가 범위 안에 있고 '.'이면 (현재 거리 + 1)을 대입

  • 'E' 종료 지점을 찾았으면 Escaped in %d minute(s)." % (board[z][x][y] + 1) 리턴
    queue가 empty가 될 때까지 종료 지점을 못찾았으면 "Trapped" 리턴


코드

# 6593 상범빌딩
from collections import deque
import sys
input = sys.stdin.readline

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


def findStart():
    for i in range(L):
        for j in range(R):
            for k in range(C):
                if board[i][j][k] == 'S':
                    board[i][j][k] = 0
                    return i, j, k

def bfs():
    while queue:
        z, x, y = queue.popleft()
        for i in range(6):
            nz = z + dz[i]
            nx = x + dx[i]
            ny = y + dy[i]
            # 범위 체크
            if 0 <= nz and nz < L and 0 <= nx and nx < R and 0 <= ny and ny < C:
                if board[nz][nx][ny] == '.':
                    board[nz][nx][ny] = board[z][x][y] + 1
                    queue.append((nz, nx, ny))

                elif board[nz][nx][ny] == 'E':
                    return "Escaped in %d minute(s)." % (board[z][x][y] + 1)

    return "Trapped!"

while True:
    L, R, C = map(int, input().split())
    if L == 0 and R == 0 and C == 0:
        break

    board = []
    for _ in range(L):
        board.append([list(input().strip()) for _ in range(R)])
        input()

    # 시작 지점 찾기
    Zstart, Xstart, Ystart = findStart()
    queue = deque()
    queue.append((Zstart, Xstart, Ystart))
    print(bfs())

0개의 댓글