로봇은 상, 하, 좌, 우 중 한 방향을 선택하면 장애물 또는 보드 경계에 닿을 때까지 미끄러진다.
로봇이 시작 위치 R에서 목표 위치 G에 정확히 멈추기 위한 최소 이동 횟수를 구한다. 목표에 도달할 수 없으면 -1을 반환한다.
한 번의 방향 선택이 한 번의 이동이고, 모든 이동의 비용이 같다. 따라서 각 정지 위치를 정점으로 보고 BFS를 수행하면 목표 위치까지의 최소 이동 횟수를 구할 수 있다.
현재 위치에서 한 방향으로 이동할 때는 한 칸씩 전진한다.
D이면 현재 위치에서 멈춘다.멈춘 위치가 다음 BFS 상태다.
R와 목표 위치 G를 찾는다.-1을 반환한다.from collections import deque
def solution(board):
row_count = len(board)
col_count = len(board[0])
start = None
goal = None
for row in range(row_count):
for col in range(col_count):
if board[row][col] == "R":
start = (row, col)
elif board[row][col] == "G":
goal = (row, col)
directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
def slide(row, col, dr, dc):
while True:
next_row = row + dr
next_col = col + dc
if (
next_row < 0
or next_row >= row_count
or next_col < 0
or next_col >= col_count
or board[next_row][next_col] == "D"
):
return row, col
row, col = next_row, next_col
visited = [[False] * col_count for _ in range(row_count)]
start_row, start_col = start
visited[start_row][start_col] = True
queue = deque([(start_row, start_col, 0)])
while queue:
row, col, move_count = queue.popleft()
if (row, col) == goal:
return move_count
for dr, dc in directions:
next_row, next_col = slide(row, col, dr, dc)
# 이미 경계 또는 장애물에 붙어 있어 움직이지 못한 경우
if (next_row, next_col) == (row, col):
continue
if not visited[next_row][next_col]:
visited[next_row][next_col] = True
queue.append((next_row, next_col, move_count + 1))
return -1
첫 번째 예시에서 로봇은 다음 순서로 이동해 목표 위치에 도착할 수 있다.
아래 -> 왼쪽 -> 위 -> 왼쪽 -> 아래 -> 오른쪽 -> 위
총 7번 이동이다.
BFS는 1번 이동으로 도달 가능한 모든 정지 위치를 먼저 확인하고, 그다음 2번 이동으로 도달 가능한 위치를 확인한다. 따라서 목표 위치를 처음 꺼냈을 때의 횟수인 7이 최소 이동 횟수다.
R을 행 수, C를 열 수라고 하자.
정지 위치 하나에서 네 방향으로 최대 max(R, C)칸을 확인한다.
O(R * C * max(R, C))O(R * C)보드의 최대 크기는 100 x 100이므로 충분히 빠르게 동작한다.
로봇이 지나가는 중간 칸이 아니라, 장애물 또는 경계 앞에서 멈춘 위치가 BFS의 상태다. 네 방향으로 미끄러진 결과만 다음 상태로 넣으면 최소 이동 횟수를 구할 수 있다.