빨강, 파랑 구슬을 보드에서 중력으로 옮겨가면서 구멍으로 빨강 구슬만 빠질 때의 최소 횟수를 구하는 문제이다.
생각했던 주요 요소는 다음과 같다.
풀이 과정은 다음과 같다.
board 배열에 벽, 구멍을 기록한다. 구슬은 따로 좌표만 가지고 있는다. 이후에 구슬 좌표를 lean 함수로 넘겨서 왼쪽, 오른쪽, 위, 아래로 기울여본다(기울이는 함수는 move).
import sys
import collections
def move(dir, i, j, another):
isOut = False
originI, originJ = i, j
if dir == 'left':
while board[i][j - 1] != '#' and [i, j - 1] != another:
j -= 1
if board[i][j] == 'O':
isOut = True
i, j = 0, 0
break
elif dir == 'right':
while board[i][j + 1] != '#' and [i, j + 1] != another:
j += 1
if board[i][j] == 'O':
isOut = True
i, j = 0, 0
break
elif dir == 'up':
while board[i - 1][j] != '#' and [i - 1, j] != another:
i -= 1
if board[i][j] == 'O':
isOut = True
i, j = 0, 0
break
else:
while board[i + 1][j] != '#' and [i + 1, j] != another:
i += 1
if board[i][j] == 'O':
isOut = True
i, j = 0, 0
break
isMove = abs(originI - i) + abs(originJ - j) > 0
return [isMove, isOut, [i, j]]
def lean():
global answer
(dir, count, red, blue) = q.pop()
redResult, blueResult = False, False
redMove, blueMove = False, False
if dir == 'left':
if red[1] < blue[1]:
[redMove, redResult, red] = move(dir, *red, blue)
[blueMove, blueResult, blue] = move(dir, *blue, red)
else:
[blueMove, blueResult, blue] = move(dir, *blue, red)
[redMove, redResult, red] = move(dir, *red, blue)
elif dir == 'right':
if red[1] > blue[1]:
[redMove, redResult, red] = move(dir, *red, blue)
[blueMove, blueResult, blue] = move(dir, *blue, red)
else:
[blueMove, blueResult, blue] = move(dir, *blue, red)
[redMove, redResult, red] = move(dir, *red, blue)
elif dir == 'up':
if red[0] < blue[0]:
[redMove, redResult, red] = move(dir, *red, blue)
[blueMove, blueResult, blue] = move(dir, *blue, red)
else:
[blueMove, blueResult, blue] = move(dir, *blue, red)
[redMove, redResult, red] = move(dir, *red, blue)
else:
if red[0] > blue[0]:
[redMove, redResult, red] = move(dir, *red, blue)
[blueMove, blueResult, blue] = move(dir, *blue, red)
else:
[blueMove, blueResult, blue] = move(dir, *blue, red)
[redMove, redResult, red] = move(dir, *red, blue)
if redResult and not blueResult:
answer = min(answer, count + 1)
return
elif (redResult and blueResult) or (not redResult and blueResult):
return
elif (redMove or blueMove) and count + 1 < answer:
for _dir in filter(lambda a: a != dir, dirs):
q.appendleft((_dir, count + 1, red, blue))
n, m = map(int, sys.stdin.readline().strip().split(' '))
board = [[] for _ in range(n)]
red, blue = None, None
dirs = ['left', 'right', 'up', 'down']
for i in range(n):
line = sys.stdin.readline().strip()
for j, l in enumerate(line):
if l == 'B':
blue = [i, j]
board[i].append('.')
elif l == 'R':
red = [i, j]
board[i].append('.')
else:
board[i].append(l)
q = collections.deque([(dir, 0, red, blue) for dir in dirs])
answer = 11
while len(q) > 0:
lean()
print(answer if answer < 11 else -1)