문제 : https://www.acmicpc.net/problem/5427
정석 풀이가 아닐수도 있습니다
풀이
요약
- 다음의 과정을 통해 풀이하였다.
- 문자열 지도를 정수형으로 변환 및 불 위치와 시작 위치 저장
- 불이 퍼지는 시간을 BFS 탐색으로 시작 위치에 기록
- 시작 위치에서 BFS로 탐색하며 탈출 가능 여부 및 시간 확인
설명
1
2
3
4
5
6
###.###
#*#.#*#
#.....#
#.....#
#..@..#
#######
- 다음과 같이 문자열로 주어진 지도를 숫자로 변환하여 IF 문을 이용하기 수월하도록 하였다.
- 먼저 h * w개의 INF 값으로 초기화된 지도를 별도로 만든다.
1
2
3
4
5
6
7
# 헷갈릴까봐 INF 대신 기호 사용
∞∞∞∞∞∞∞
∞∞∞∞∞∞∞
∞∞∞∞∞∞∞
∞∞∞∞∞∞∞
∞∞∞∞∞∞∞
∞∞∞∞∞∞∞
- 이제 한 줄씩 문자열을 입력받으면서, for loop를 통해 각 구역이 어떤 종류인지 확인한다.
- 빈 공간(
.
)이면 그대로 둠 - 벽(
#
)이면 -1로 변환 - 불(
*
)이면 해당 위치를 별도 배열에 저장하고 0으로 변환 - 상근이의 시작 위치(
@
)면 시작 위치 변수에 저장
- 빈 공간(
- 모든 입력을 받고나면 아래와 같은 상태가 된다. ``` -1 -1 -1 ∞ -1 -1 -1 -1 0 -1 ∞ -1 0 -1 -1 ∞ ∞ ∞ ∞ ∞ -1 -1 ∞ ∞ ∞ ∞ ∞ -1 -1 ∞ ∞ ∞ ∞ ∞ -1 -1 -1 -1 -1 -1 -1 -1
불 위치 저장 변수
fires < [(1, 1), (1, 5)]
시작 위치
start = (4, 3)
1
2
3
4
5
6
- 이제 불 위치를 저장한 변수를 꺼내어 BFS 탐색을 하면서 지도에 어느 시간에 불이 번지는지를 기록한다.
- for loop을 통해 `fires`에 저장된 좌표를 하나씩 꺼내어 지도를 갱신한다.
- BFS 탐색시 `time` 변수를 두어 현재 time보다 큰 값으로만 이동할 수 있도록 하면 방문체크를 하지 않아도 된다.
for x, y in fires: (1, 1) -1 -1 -1 5 -1 -1 -1 -1 0 -1 4 -1 0 -1 -1 1 2 3 4 5 -1 -1 2 3 4 5 6 -1 -1 3 4 5 6 7 -1 -1 -1 -1 -1 -1 -1 -1
(1, 5) -1 -1 -1 5 -1 -1 -1 -1 0 -1 4 -1 0 -1 -1 1 2 3 2 1 -1 -1 2 3 4 3 2 -1 -1 3 4 5 4 3 -1 -1 -1 -1 -1 -1 -1 -1
1
2
3
4
5
6
7
- 이제 시작 위치부터 BFS 탐색을 시작한다.
- 상근이가 떠남과 동시에 불이 옮겨 붙는 것은 상관 없으므로, 불이 붙는 시간을 갱신할 때와 마찬가지로 `time` 변수를 두어 현재 time 보다 큰 값으로 이동할 수 있도록 한다.
- 중복 방문을 방지하기 위해 현재 time으로 board를 갱신하였으나, 생각해보니 board를 다시 사용하지 않으므로 그냥 0으로 초기화해도 될 것 같다.
- 상근이가 이동할 위치가 이차원 리스트의 index 범위를 벗어난 곳이면 탈출했다는 뜻이므로 이동 시간을 반환하고, 모든 BFS 탐색이 끝날 때까지 탈출하지 못하면 `IMPOSSIBLE`을 반환한다.
상근이 이동 후 지도
-1 -1 -1 4 -1 -1 -1 -1 0 -1 3 -1 0 -1 -1 1 2 2 2 1 -1 -1 2 2 1 2 2 -1 -1 2 1 0 1 2 -1 -1 -1 -1 -1 -1 -1 -1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
## 코드
```python
import sys
from collections import deque
input = sys.stdin.readline
INF = 2147000000
T = int(input())
DX = [-1, 0, 1, 0]
DY = [0, 1, 0, -1]
def BFS(start, board):
que = deque()
que.append((start[0], start[1], 1))
while que:
x, y, time = que.popleft()
for n in range(4):
xx = x + DX[n]
yy = y + DY[n]
# 우선 탈출 여부 체크
if 0 <= xx < h and 0 <= yy < w:
# 이동할 수 있는 경우
if time < board[xx][yy]:
board[xx][yy] = time
que.append((xx, yy, time+1))
# 인덱스를 벗어난 경우는 탈출한 것
else:
return time
return 'IMPOSSIBLE'
for _ in range(T):
w, h = map(int, input().split())
# 실제로 사용할 지도를 초기화
board = [[INF] * w for _ in range(h)]
fires = []
# 빌딩 입력받기
for i in range(h):
temp = input().rstrip()
for j in range(w):
if temp[j] == '.':
continue
if temp[j] == '#':
board[i][j] = -1
elif temp[j] == '*':
board[i][j] = 0
fires.append((i, j))
else:
board[i][j] = -1
start = (i, j)
# 불이 번지는 시간을 보드에 기록
for i, j in fires:
que = deque()
que.append((i, j, 1))
while que:
x, y, time = que.popleft()
for n in range(4):
xx = x + DX[n]
yy = y + DY[n]
# 이미 다른 곳에서 옮겨붙는 불이 있으면 탐색 X
if 0 <= xx < h and 0 <= yy < w and time < board[xx][yy]:
board[xx][yy] = time
que.append((xx, yy, time+1))
# 사람 탐색
print(BFS(start, board))
추가 문제
3055. 탈출도 동일한 방법으로 풀 수 있다.
This post is licensed under CC BY 4.0 by the author.