BOJ 13460: 구슬 탈출 2 https://www.acmicpc.net/problem/13460
import sys
from collections import deque
N, M = map(int, sys.stdin.readline().rstrip().split())
board = [list(sys.stdin.readline().rstrip()) for _ in range(N)]
dx = [0, 0, -1, 1]
dy = [1, -1, 0, 0]
# 빨간 구슬, 파란 구슬이 위치한 상태를 기록하기 위한 4차원 배열
visited = [[[[False for _ in range(M)] for _ in range(N)] for _ in range(M)] for _ in range(N)]
# 입력받은 방향으로 공을 끝까지 굴리는 함수
def roll(x, y, direction):
cnt = 0
while True:
nx = x + dx[direction]
ny = y + dy[direction]
# 다음 위치가 벽이거나 현재 위치가 구멍('O')이면 종료
if board[nx][ny] == '#' or board[x][y] == 'O':
break
x = nx
y = ny
cnt += 1
# 마지막 위치와 굴러간 횟수 반환
return x, y, cnt
# BFS를 사용해 빨간 구슬과 파란 구슬을 동시에 굴리며 답 찾기
def bfs(ra, rb, ba, bb):
que = deque()
que.append([ra, rb, ba, bb, 1])
while que:
rx, ry, bx, by, move_cnt = que.popleft()
# 현재 상황 기록
visited[rx][ry][bx][by] = True
# 판을 기울인 회수가 10 넘어가면 종료
if move_cnt > 10:
return -1
# 다음 방향으로 굴린 결과 확인
for t in range(4):
# 빨간 구슬 결과
nrx, nry, rcnt = roll(rx, ry, t)
# 파란 구슬 결과
nbx, nby, bcnt = roll(bx, by, t)
# 파란 구슬이 구멍('O')에 없을 때 (파란 구슬이 구멍('O')에 있는 상황은 걸러냄)
if board[nbx][nby] != 'O':
# 빨간 구슬이 구멍('O')에 도달하면 종료
if board[nrx][nry] == 'O':
return move_cnt
# 두 공이 겹치면 앞뒤 구분해서 재배치
if nrx == nbx and nry == nby:
# 구슬이 더 많이 구름 -> 더 뒤쪽이었다는 뜻
if rcnt > bcnt:
nrx -= dx[t]
nry -= dy[t]
else:
nbx -= dx[t]
nby -= dy[t]
# 굴린 결과가 아직 겪지 않은 상황이면
if not visited[nrx][nry][nbx][nby]:
# 겪은 상황이라고 체크
visited[nrx][nry][nbx][nby] = True
# 큐에 넣기
que.append([nrx, nry, nbx, nby, move_cnt + 1])
# 게임을 종료할 수 없으면 -1 반환하고 종료
return -1
a, b, c, d = 0, 0, 0, 0
for i in range(N):
for j in range(M):
if board[i][j] == 'R':
a = i
b = j
if board[i][j] == 'B':
c = i
d = j
result = bfs(a, b, c, d)
print(result)