주어진 정사각형의 방에서 로봇 청소기가 가구를 피해 더러운 칸을 모두 방문하기 위한 최단 경로의 길이를 구하면 되는 문제
import sys
from typing import List, Tuple
from collections import deque
from itertools import product, permutations
input = sys.stdin.readline
dy = [-1, 1, 0, 0]
dx = [0, 0, -1, 1]
def bfs(
matrix: List[List[str]],
st: Tuple[int, int],
dt: Tuple[int, int],
) -> int:
"""
주어진 matrix에서 두 점 사이의 최단 거리를 구해 반환한다.
"""
visited = [[False for _ in range(w)] for _ in range(h)]
queue = deque([(*st, 0)])
visited[st[0]][st[1]] = True
while queue:
y, x, cnt = queue.popleft()
if (y, x) == dt:
return cnt
for d in range(4):
ny, nx = y + dy[d], x + dx[d]
if (
0 <= ny < h
and 0 <= nx < w
and not visited[ny][nx]
and matrix[ny][nx] != "x"
):
queue.append((ny, nx, cnt + 1))
visited[ny][nx] = True
return -1
def get_distance_matrix(
matrix: List[List[str]], points: List[Tuple[int, int]]
) -> List[List[int]]:
"""
로봇청소기와 더러운 칸, 더러운 칸과 더러운 칸의 모든 거리를 저장한 distance matrix를 만들어 반환한다.
points = 로봇청소기 위치 + 더러운칸 위치(robot_and_dirty_place)
"""
distance_matrix = [[0 for _ in range(len(points))] for _ in range(len(points))]
for st, dt in product(
range(len(points)), range(len(points))
): # 모든 (시작점 idx, 도착점 idx) 집합을 순회한다.
if distance_matrix[st][dt]: # distance matrix는 대칭이므로 이전 연산에 의해 이미 저장되어있는 경우
continue
distance = bfs(
matrix, points[st], points[dt]
) # matrix에서 두 점사이의 최단 거리는 bfs로 구한다.
if distance == -1: # 탐색에 실패하는 경우(더러운 칸에 갈 수 없는 경우)
return -1 # 실패 반환
else:
distance_matrix[st][dt] = distance_matrix[dt][
st
] = distance # distance_matrix는 대칭
return distance_matrix
def get_min_path(distance_matrix: List[List[int]]) -> int:
"""
주어진 distance_matrix에서 최단 이동 경로를 구해 반환한다.
"""
min_path = 1000000
for case in permutations(
range(1, len(distance_matrix))
): # 더러운 곳 탐색 순서의 모든 경우의 수 탐색(최대 10!), 0번째는 로봇 위치임
tmp = distance_matrix[0][case[0]] # 로봇 -> 첫 번째 더러운 곳
for i in range(len(case) - 1): # 더러운 곳 -> 더러운 곳
tmp += distance_matrix[case[i]][case[i + 1]]
min_path = min(min_path, tmp) # 최단 이동 경로 업데이트
return min_path
def start_simulation(
matrix: List[List[str]],
dirty_places: List[Tuple[int, int]],
robot_idx: Tuple[int, int],
) -> int:
"""
주어진 조건에서 최단 이동경로를 찾기 위한 시뮬레이션을 시작한다.
1. 모든 더러운 칸끼리의 거리를 저장한 distance matrix생성한다. (로봇 포함)
1-1. distance_matrix 만들기에 실패하면 -1을 반환한다.
2. 주어진 distance_matrix에서 최단 이동 경로를 구해 반환한다.
"""
robot_and_dirty_place = [robot_idx] + dirty_places # 로봇과 더러운 칸과의 거리도 알아야 하므로 위치 합치기
distance_matrix = get_distance_matrix(matrix, robot_and_dirty_place)
if distance_matrix == -1:
return -1
return get_min_path(distance_matrix)
def simulation() -> int:
"""
주어진 각 테스트케이스마다 시뮬레이션을 위한 셋업(matrix만들기, 로봇 위치, 더러운 칸 위치) 후 시뮬레이션을 호출한다.
"""
matrix = []
dirty_places = []
robot_idx = None
for r in range(h):
row = list(input().rstrip())
for c in range(w):
if not robot_idx and row[c] == "o": # 로봇은 한 대만 주어짐
robot_idx = (r, c)
if row[c] == "*":
dirty_places.append((r, c))
matrix.append(row)
return start_simulation(matrix, dirty_places, robot_idx) # 최단 이동 경로를 얻기 위한 시뮬레이션 시작
while True:
w, h = map(int, input().rstrip().split())
if not h:
break
print(simulation())
🙏 문제 접근 방법 및 코드에 대한 피드백과 질문은 환영입니다!
본 문제의 다른 풀이 및 피드백, 전체 문제 풀이 순서는 위 알고리즘 스터디 Repository에서도 확인 가능합니다.