반응형
https://www.acmicpc.net/problem/9328
9328번: 열쇠
상근이는 1층 빌딩에 침입해 매우 중요한 문서를 훔쳐오려고 한다. 상근이가 가지고 있는 평면도에는 문서의 위치가 모두 나타나 있다. 빌딩의 문은 모두 잠겨있기 때문에, 문을 열려면 열쇠가
www.acmicpc.net
BFS를 응용한 단순 구현문제이다.
내가 푼 알고리즘은 다음과 같다.
1. 외곽을 모두 돌면서 빈공간의 위치를 덱에 넣고,
열쇠는 먹은 후 빈공간으로 바꾼다음 위치를 덱에 넣고,
문은 맵에 문 위치를 저장한다.
(이때 같은 문이 여러개 있을 수 있으니, 맵에 리스트를 저장한다.)
(열쇠는 같은 열쇠가 여러개 있을 수 있으니 집합에 저장한다.)
2. 현재 갖고 있는 열쇠로 열 수 있는 문을 모두 연다.
문을 열고나면 해당 공간을 빈 공간으로 만들고, 그 위치를 덱에 넣는다.
열린 문은 맵에서 제거한다.
3. 덱에 저장된 내용으로 BFS를 돌린다.
4. BFS를 돌면서 지나갈 수 있는 모든 곳을 지나가며 열쇠를 먹는다.
5. BFS가 끝나기 직전에는 (덱에 아무 내용도 없을 때)
현재 갈 수 있는 모든 곳을 다 순회하면서 먹을 수 있는 열쇠도 다 먹은 상태이다.
이 상태에서 다시 모든 문을 열고 문 정보를 맵에서 제거하고 문위치를 덱에 넣어
열린 문에서부터 다시 BFS를 돈다.
이 과정을 반복하면서 중간 중간 만난 비밀문서의 개수를 센다.
import sys
from collections import deque
input = sys.stdin.readline
TEST_MODE = True
dh = [0, 0, 1, -1]
dw = [-1, 1, 0, 0]
def printBoard(_board):
global h
if not TEST_MODE:
return
for ii in range(h):
print(_board[ii])
print()
def openAllDoor():
for key in keys:
while doors[key.upper()]:
door_h, door_w = doors[key.upper()].pop()
board[door_h][door_w] = '.'
d.append((door_h, door_w))
visit[door_h][door_w] = True
t = int(input())
for _ in range(t):
h, w = map(int, input().split())
board = []
for __ in range(h):
board.append(list(input().rstrip()))
keys = list(input().rstrip())
if keys[0] == '0':
keys = set()
else:
keys = set(keys)
d = deque()
visit = [[False for _ in range(w)] for _ in range(h)]
doors = {}
for c in list('ABCDEFGHIJKLMNOPQRSTUVWXYZ'):
doors[c] = []
#print(doors)
answer = 0
# 외곽을 체크하면서 빈공간 찾기, 첫 외곽을 돌 때는 방문 배열이 모두 false 이므로 체크할 필요가 없다.
for i in range(h):
for j in range(w):
if 0 < i < h-1 and 0 < j < w-1:
continue
if board[i][j] == '*':
continue
if board[i][j] == '.':
d.append((i, j))
visit[i][j] = True
elif board[i][j] == '$':
answer += 1
board[i][j] = '.'
d.append((i, j))
visit[i][j] = True
elif 'a' <= board[i][j] <= 'z':
keys.add(board[i][j])
board[i][j] = '.'
d.append((i, j))
visit[i][j] = True
elif 'A' <= board[i][j] <= 'Z':
# 문은 지금 열 수 있어도 바로 열지 않고, 모든 외곽 체크를 끝내고 열쇠를 먹은 만큼 다 먹고나면 그때부터 문 열기.
# 지금 열면 구현할 때 실수하기 쉬워진다.
doors[board[i][j]].append((i, j))
# 문열기
openAllDoor()
while d:
now_h, now_w = d.popleft()
for k in range(4):
check_h = now_h + dh[k]
check_w = now_w + dw[k]
if 0 <= check_h < h and 0 <= check_w < w:
if board[check_h][check_w] == "." and not visit[check_h][check_w]:
d.append((check_h, check_w))
visit[check_h][check_w] = True
elif board[check_h][check_w] == "$":
answer += 1
board[check_h][check_w] = '.'
d.append((check_h, check_w))
visit[check_h][check_w] = True
elif 'a' <= board[check_h][check_w] <= 'z': # 열쇠가 있다는 것은 방문하지 않았다. (방문후에는 빈칸으로 바꾸고 있으니까)
keys.add(board[check_h][check_w])
board[check_h][check_w] = '.'
d.append((check_h, check_w))
visit[check_h][check_w] = True
elif 'A' <= board[check_h][check_w] <= 'Z': # 문을 만나면 문을 저장
doors[board[check_h][check_w]].append((check_h, check_w))
# 만약 방문을 다 해서 덱이 비어있다면, BFS가 끝났으므로 문을 열고 연 위치부터 이어서 다시 BFS 진행
if not d:
openAllDoor()
print(answer)
반응형
'알고리즘 (PS) > BOJ' 카테고리의 다른 글
[백준] 4386 - 별자리 만들기 (G4) (0) | 2021.12.13 |
---|---|
[백준] 10942 - 펠린드롬? (G3) (0) | 2021.12.12 |
[백준] 1202 - 보석도둑 (G2) (0) | 2021.12.08 |
[백준] 1647 - 도시 분할 계획 (G4) (0) | 2021.12.07 |
[백준] 13460 - 구슬 탈출 2 (G1) (0) | 2021.12.04 |