BFS - 19238번: 스타트 택시

jisu_log·2025년 5월 8일

알고리즘 문제풀이

목록 보기
26/105

# 택시에서 가장 가까운 손님부터 태움(여러개면 행이 작은 손님부터)

# 택시가 한 칸 움직일때마다 연료는 1씩 감소
# 택시가 승객에게 가는 데 연료 소모되고, 목적지까지 가는데 연료 소모됨

# 택시가 목적지에 도달하면 승객이 탄 시점부터 목적지까지 가는데 사용한 연료의 두배만큼 충전됨
# 택시가 가다가 중간에 연료를 다쓰면 종료 (도착지에 도착하면서 다쓴건 종료 아님)

# 모든 승객을 데려다줄 수 있는지? 가능하면 마지막에 남은 연료 양 출력하기
import sys
from collections import deque

input = sys.stdin.readline

line = list(map(int, input().split()))
n, m, fuel = line[0], line[1], line[2]
maps = []  # 0: 빈공간, 1: 벽, 2: 승객

for i in range(0, n):
    lines = list(map(int, input().split()))
    maps.append(lines)

taxi_x, taxi_y = map(int, input().split())
taxi_x -= 1
taxi_y -= 1
user_list = {}  # 승객별 목적지 저장 딕셔너리(키: 승객 좌표, 값: 목적지 좌표)

for i in range(0, m):
    lines = list(map(int, input().split()))
    start_x, start_y = lines[0] - 1, lines[1] - 1
    maps[start_x][start_y] = 2
    user_list[(start_x, start_y)] = [lines[2] - 1, lines[3] - 1]

# 상, 좌 부터 탐색하도록 함 (거리 상 가까운 승객이 둘이면 행, 열이 작은 손님부터 태워야하므로)
dx = [-1, 0, 1, 0]
dy = [0, -1, 0, 1]

# 택시 운행 스타트


def go_to_destination(maps, x, y):

    visited = []
    for j in range(n):
        visited.append([False] * n)

    visited[x][y] = True
    dest_x, dest_y = user_list[(x, y)]

    queue = deque([(x, y, 0)])
    while queue:
        x, y, dist = queue.popleft()

        # 목적지 도착하면 현재 거리 리턴(bfs는 최단거리 보장되므로)
        if x == dest_x and y == dest_y:
            return dist

        for i in range(4):
            nx, ny = x + dx[i], y + dy[i]
            # 가고자 하는 곳이 맵 내부고, 벽이 아니고, 방문한 곳이 아니라면
            if (
                0 <= nx < n
                and 0 <= ny < n
                and maps[nx][ny] != 1
                and not visited[nx][ny]
            ):
                visited[nx][ny] = True
                queue.append((nx, ny, dist + 1))

    return -1


# bfs로 현재 택시로부터 가장 가까운 위치의 승객을 찾기 (소요되는 연료도 구하기)
def find_user(maps, x, y):
    if maps[x][y] == 2:
        return 0, x, y

    visited = []
    for j in range(n):
        visited.append([False] * n)
    visited[x][y] = True

    candidates = []
    min_dist = -1  # 찾은 최소 거리

    queue = deque([(x, y, 0)])
    while queue:
        x, y, dist = queue.popleft()

        # 이미 승객을 찾았고, 그 최소 거리보다 거리가 더 커지면 더 볼 필요 없으므로 종료
        # if min_dist != -1 and dist >= min_dist:
        #    break

        for i in range(4):
            nx, ny = x + dx[i], y + dy[i]
            # 가고자 하는 곳이 맵 내부고, 벽이 아니고, 방문한 곳이 아니라면
            if (
                0 <= nx < n
                and 0 <= ny < n
                and maps[nx][ny] != 1
                and not visited[nx][ny]
            ):
                visited[nx][ny] = True
                # 승객을 찾았다면
                if maps[nx][ny] == 2:
                    # 거리는 한 칸 더 가야 승객 위치이므로 + 1
                    candidates.append([dist + 1, nx, ny])
                    min_dist = dist + 1
                    # 여기서 찾았다고 break 하지 않기! 거리가 동일한 다른 손님도 찾아야 하므로
                else:
                    queue.append((nx, ny, dist + 1))

    if candidates:
        candidates.sort()
    # 승객에게 도달할 수 없다면
    else:
        return -1, -1, -1

    # 가장 가까운 승객의 좌표 및 거리 리턴
    return candidates[0][0], candidates[0][1], candidates[0][2]


all_clear = True

# 모든 승객에 대해서
for i in range(0, m):
    # 현재 위치에서 가장 가까운 승객 찾기

    dist, user_x, user_y = find_user(maps, taxi_x, taxi_y)
    if user_x == -1 and user_y == -1:
        all_clear = False
        break
    # 현재 연료로 갈 수 있다면, 승객 위치로 택시 이동, 거리만큼 연료 소모
    if fuel >= dist:
        taxi_x, taxi_y = user_x, user_y
        fuel -= dist
        # 승객 태워서 목적지까지 이동할 수 있는지 체크
        min_dist = go_to_destination(maps, taxi_x, taxi_y)

        # -1 예외처리
        if min_dist == -1:
            all_clear = False
            break

        # 목적지까지 이동 가능하면
        if fuel >= min_dist:
            # 승객 태워서
            maps[taxi_x][taxi_y] = 0
            # 택시를 목적지로 위치 이동
            dest_x, dest_y = user_list[(taxi_x, taxi_y)]
            taxi_x, taxi_y = dest_x, dest_y
            del user_list[(user_x, user_y)]
            # 연료 소모
            fuel -= min_dist
            # 택시가 목적지에 도달하면 승객이 탄 시점부터 목적지까지 가는데 사용한 연료의 두배만큼 충전됨
            fuel += min_dist * 2
        else:
            all_clear = False
            break
    else:
        all_clear = False
        break

if not all_clear:
    print("-1")
else:
    print(fuel)

0개의 댓글