문제 설명
문제
지훈이는 미로에서 일을 한다. 지훈이를 미로에서 탈출하도록 도와주자!
미로에서의 지훈이의 위치와 불이 붙은 위치를 감안해서 지훈이가 불에 타기전에 탈출할 수 있는지의 여부, 그리고 얼마나 빨리 탈출할 수 있는지를 결정해야한다.
지훈이와 불은 매 분마다 한칸씩 수평또는 수직으로(비스듬하게 이동하지 않는다) 이동한다.
불은 각 지점에서 네 방향으로 확산된다.
지훈이는 미로의 가장자리에 접한 공간에서 탈출할 수 있다.
지훈이와 불은 벽이 있는 공간은 통과하지 못한다.
입력
입력의 첫째 줄에는 공백으로 구분된 두 정수 R과 C가 주어진다. 단, 1 ≤ R, C ≤ 1000 이다. R은 미로 행의 개수, C는 열의 개수이다.
다음 입력으로 R줄동안 각각의 미로 행이 주어진다.
각각의 문자들은 다음을 뜻한다.
- #: 벽
- .: 지나갈 수 있는 공간
- J: 지훈이의 미로에서의 초기위치 (지나갈 수 있는 공간)
- F: 불이 난 공간
J는 입력에서 하나만 주어진다.
출력
지훈이가 불이 도달하기 전에 미로를 탈출 할 수 없는 경우 IMPOSSIBLE 을 출력한다.
지훈이가 미로를 탈출할 수 있는 경우에는 가장 빠른 탈출시간을 출력한다.
풀이 과정
- 전체적으로 소스가 길어지는 문제인거 같음..
- 현재 지훈이의 위치를 큐에 넣어준다.
- 현재 불의 위치를 구해 준다.
- bfs를 활용하여 큐의 맨 앞에서부터 위치를 빼주면서 지훈이가 갈수있는 위치를 큐에 넣어준다.
- 이 과정을 하다 보면 이동 횟수가 바뀌는 시점이 존재한다.
- 이동 횟수가 바뀌는 시점에 bfs를 통해 불을 확산시킨다, 이 때, 매 순간 반복문으로 불의 위치를 찾으면 시간 초과가 난다.
- 따라서.. 한번 확산시키면서, 확산된 불의 위치 또한 큐에 저장해두어야 한다.
- 배열의 범위를 넘게되는 순간 탈출한 것이므로 그때의 이동 횟수를 출력하고 종료한다.
- 만약 (4)를 실행하지 않고 큐의 요소가 비게 되면 탈출이 불가능한 것이므로 IMPOSSIBLE을 출력해 준다.
- 소스가 조금 복잡하게 짜여 있음.
import sys
from collections import deque
input = sys.stdin.readline
# 불 확산 함수
Fire = deque()
def spread(matrix, R, C):
global Fire
stop_flag = 0
if Fire:
stop_flag = Fire[0][2]
dx = [-1, 1, 0, 0]
dy = [0, 0, 1, -1]
while Fire:
if Fire[0][2] > stop_flag:
break
cx, cy, step = Fire.popleft()
for i in range(4):
nx = cx + dx[i]
ny = cy + dy[i]
if 0 <= nx and nx < R and 0 <= ny and ny < C:
if matrix[nx][ny] == '.' or matrix[nx][ny] == 'J':
matrix[nx][ny] = 'F'
Fire.append([nx, ny, step+1])
R, C = map(int, input().rstrip().split())
matrix = [list(input().rstrip()) for _ in range(R)]
for i in range(R):
for j in range(C):
if matrix[i][j] == 'F':
Fire.append([i, j, 0])
J_x, J_y = 0, 0
flag = False
# 지훈이의 위치 찾음
for i in range(R):
for j in range(C):
if matrix[i][j] == 'J':
J_x, J_y = i, j
flag = True
break
if flag:
break
Jh_queue = deque([[J_x, J_y, 0]])
visited = set()
dx = [-1, 1, 0, 0]
dy = [0, 0, 1, -1]
last = 0
visited.add((J_x, J_y))
answer_flag = False
answer = 0
while Jh_queue:
jx, jy, movement_count = Jh_queue.popleft()
# 이동 횟수가 늘어나면 불 확산
if last != movement_count:
spread(matrix, R, C)
last = movement_count
# 현재 방문하려는 위치에 이미 불 퍼진 상태면 스킵
if matrix[jx][jy] == 'F':
continue
for i in range(4):
nx, ny = jx + dx[i], jy + dy[i]
if 0 <= nx and nx < R and 0 <= ny and ny < C:
if matrix[nx][ny] == '.' and (nx, ny) not in visited:
Jh_queue.append([nx, ny, movement_count+1])
visited.add((nx, ny))
elif 0 > nx or nx >= R or 0 > ny or ny >= C:
answer_flag = True
answer = movement_count + 1
break
if answer_flag:
break
if answer_flag:
print(answer)
else:
print("IMPOSSIBLE")
'알고리즘[Python] > 백준 알고리즘' 카테고리의 다른 글
[ 1822 ] 차집합 (0) | 2021.08.01 |
---|---|
[ 1918 ] [Stack] 후위 표기식 (0) | 2021.07.31 |
[ 2331 ] 반복 수열 (0) | 2021.07.30 |
[ 10451 ] [DFS] 순열 사이클 (0) | 2021.07.30 |
[ 2491 ] [DP] 수열 (0) | 2021.07.29 |