[백준] #1504 특정한 최단 경로(python)

수영·2022년 9월 20일

백준

목록 보기
62/117
post-thumbnail

📌문제

방향성이 없는 그래프가 주어진다. 세준이는 1번 정점에서 N번 정점으로 최단 거리로 이동하려고 한다. 또한 세준이는 두 가지 조건을 만족하면서 이동하는 특정한 최단 경로를 구하고 싶은데, 그것은 바로 임의로 주어진 두 정점은 반드시 통과해야 한다는 것이다.

세준이는 한번 이동했던 정점은 물론, 한번 이동했던 간선도 다시 이동할 수 있다. 하지만 반드시 최단 경로로 이동해야 한다는 사실에 주의하라. 1번 정점에서 N번 정점으로 이동할 때, 주어진 두 정점을 반드시 거치면서 최단 경로로 이동하는 프로그램을 작성하시오.

입력

첫째 줄에 정점의 개수 N과 간선의 개수 E가 주어진다. (2 ≤ N ≤ 800, 0 ≤ E ≤ 200,000) 둘째 줄부터 E개의 줄에 걸쳐서 세 개의 정수 a, b, c가 주어지는데, a번 정점에서 b번 정점까지 양방향 길이 존재하며, 그 거리가 c라는 뜻이다. (1 ≤ c ≤ 1,000) 다음 줄에는 반드시 거쳐야 하는 두 개의 서로 다른 정점 번호 v1과 v2가 주어진다. (v1 ≠ v2, v1 ≠ N, v2 ≠ 1) 임의의 두 정점 u와 v사이에는 간선이 최대 1개 존재한다.

출력

첫째 줄에 두 개의 정점을 지나는 최단 경로의 길이를 출력한다. 그러한 경로가 없을 때에는 -1을 출력한다.

예제 입력

4 6
1 2 3
2 3 3
3 4 1
1 3 5
2 4 5
1 4 4
2 3

예제 출력

7

백준 1504번 문제

💡Idea

👩‍🏫 다익스트라 알고리즘을 이용하면 쉽게 풀 수 있는 문제입니다.

다익스트라 알고리즘에 대해 더 자세히 알고 싶다면?

이 문제에서는 임의의 두✌ 정점을 반드시 지나는 최단 경로를 구해야 합니다.
임의의 두 정점을 각각 V1, V2라고 할 때, 우리는 이 두 정점을 지나 정점 N으로 갈 수 있는 경우를 아래와 같이 두 가지로 생각해 볼 수 있습니다.

최단 거리를 구해야 하기 때문에 우리는 둘 중 더 작은 경로를 선택하면 됩니다.

1. 1 -> V1 -> V2 -> N
➡ (1번 노드에서 V1로 가는 최단 거리 + V1번 노드에서 V2로 가는 최단 거리 + V2번 노드에서 N로 가는 최단 거리 )
  \;
2. 1 -> V2 -> V1 -> N
➡ (1번 노드에서 V2로 가는 최단 거리 + V2번 노드에서 V1로 가는 최단 거리 + V1번 노드에서 N로 가는 최단 거리 )

그리고, 이 문제의 그래프는 방향성이 없는 그래프입니다.
따라서 아래와 같은 사실을 통해 다익스트라 알고리즘의 실행 수를 줄일 수 있습니다!

1 -> V1 == V1 -> 1
1 -> V2 == V2 -> 1

💻코드

  • ⏰ 시간 : 488 ms / 메모리 : 63692 KB
import heapq
import sys
input = sys.stdin.readline
INF = sys.maxsize # 임의로 무한댓 값 정의


def dijkstra(start): # 다익스트라 함수
    distance = [INF for _ in range(N+1)] 
    distance[start] = 0 
    hq = [(0, start)] 
    while hq:
        dis, node = heapq.heappop(hq)
        if distance[node] < dis: continue
        for n, d in graph[node]:
            if distance[n] > distance[node] + d:
                distance[n] = distance[node] + d
                heapq.heappush(hq, (distance[n], n))
    return distance


N, E = map(int, input().split())
graph = {n : [] for n in range(1, N+1)}

for _ in range(E):
    a, b, c = map(int, input().split())
    graph[a].append((b, c))
    graph[b].append((a, c))

V1, V2 = map(int, input().split()) # 지나야 하는 임의의 두 정점

V1_distance = dijkstra(V1) # V1이 시작 정점인 경우의 각 최단 거리
V2_distance = dijkstra(V2) # V2이 시작 정점인 경우의 각 최단 거리

# 1 -> V1 -> V2 -> N과 1-> V2 -> V1 -> N 중 더 짧은 경로 선택
route = min(V1_distance[1] + V1_distance[V2] + V2_distance[N],
            V2_distance[1] + V2_distance[V1] + V1_distance[N])
print(route if route < INF else -1) # 거리가 INF라면 최단 경로가 존재하지 않음

📝코드 설명

변수

  • graph : 각 간선의 거리를 저장하는 딕셔너리로, {a : [(b, c)]}ab를 연결하는 간선의 거리가 c라는 뜻입니다.
  • distance : start 정점으로부터 각 노드로의 최단 거리를 저장하는 리스트입니다.

📌 이 때, 유의해야 할 점이 있습니다!

임의의 두 정점을 지나는 최단 경로가 존재하지 않는다면, -1을 출력해야 한다는 것을 고려해야 합니다.

만약, 다익스트라를 사용하여 구한 최단 거리가 INF라면 임의의 두 정점을 지나 N으로 가는 거리가 존재하지 않는다는 의미이기 때문에 -1을 출력해줘야 합니다.

profile
하고 싶은 건 그냥 죽도록 합니다

0개의 댓글