알고리즘 문제

백준 1504번 : 특정한 최단 경로 in Python

YJH3968 2021. 5. 1. 23:36
728x90

이 문제는 이전의 가중치를 포함한 최단 경로 문제에서 특정 두 정점을 항상 지나야 한다는 조건이 붙은 문제이다.

만약 최단 경로에 조건에 있는 두 정점이 있는 경우에는 아무 문제가 없다. 그냥 정점 1에서 정점 N까지의 최단 경로의 길이를 출력하면 된다. 문제는 그렇지 않은 경우로, 이는 크게 두 가지 경우로 나눌 수 있다. 두 정점을 v1, v2라 할 때 v1을 먼저 갔다가 v2를 가고, 마지막으로 N으로 가는 방법과, v2를 먼저 갔다가 v1을 가고, 마지막으로 N으로 가는 방법이 있다. 물론 각 정점을 경유할 때마다 그 정점들 사이에서는 최단 경로로 움직여야 할 것이고, 따라서 각 정점마다 그 정점을 시작점으로 하는 Dijkstra 알고리즘을 실행해야 할 것이다.

이를 구현하기 위해 우선 Dijkstra 알고리즘을 시작점을 매개변수로 받는 함수로 만들고 시작점이 1일 때, v1일 때, 그리고 v2일 때 각각 Dijkstra 알고리즘 구현 함수를 실행해 그 결과 나온 각 경우에 대해 최단 거리를 저장한 배열을 얻는다. 그리고 이제 v1 -> v2 -> N 순서대로 경유했을 때 최단 거리와 v2 -> v1 -> N 순서대로 경유했을 때 최단 거리를 비교해 더 작은 값을 출력하면 된다. 단, 만약 v1, v2를 지나는 경로가 존재하지 않을 시 두 값 모두 sys.maxsize(INF)일 것이므로 이 경우에는 -1을 출력한다.

이를 코드로 구현하면 다음과 같다.

import sys
import heapq
N, E = map(int, input().split())
graph = [[] for _ in range(N+1)]
for _ in range(E):
    a, b, c = map(int, input().split())
    graph[a].append([b, c])
    graph[b].append([a, c])
# 시작점을 매개변수로 받는 Dijkstra 알고리즘 구현 함수
def Dijkstra(v):
    global N
    dijk = [sys.maxsize for _ in range(N+1)]
    visit = [False for _ in range(N+1)]
    dijk[v] = 0
    heap = []
    heapq.heappush(heap, [0, v])
    while len(heap) > 0:
        [d, u] = heapq.heappop(heap)
        if visit[u] == True: continue
        visit[u] = True
        for [v, w] in graph[u]:
            if dijk[v] > dijk[u] + w:
                dijk[v] = dijk[u] + w
                heapq.heappush(heap, [dijk[v], v])
    # 시작점에서 출발했을 때 그래프의 각 정점까지의 최단 거리를 저장한 배열을 반환한다.
    return dijk
v1, v2 = map(int, input().split())
# 1, v1, v2에 대해 Dijkstra 알고리즘 함수를 실행한다.
dijk1 = Dijkstra(1)
dijk2 = Dijkstra(v1)
dijk3 = Dijkstra(v2)
# 1 -> v1 -> v2 -> N, 1 -> v2 -> v1 -> N 중 더 짧은 경로의 길이를 정한다.
res = min(dijk1[v1] + dijk2[v2] + dijk3[N], dijk1[v2] + dijk3[v1] + dijk2[N])
if res < sys.maxsize:
    print(res)
# v1과 v2를 경유해 N에 도달하는 경로가 없는 경우 -1을 출력한다.
else:
    print(-1)

 

728x90