문제
방향성이 없는 그래프가 주어진다. 세준이는 1번 정점에서 N번 정점으로 최단 거리로 이동하려고 한다. 또한 세준이는 두 가지 조건을 만족하면서 이동하는 특정한 최단 경로를 구하고 싶은데, 그것은 바로 임의로 주어진 두 정점은 반드시 통과해야 한다는 것이다.
세준이는 한번 이동했던 정점은 물론, 한번 이동했던 간선도 다시 이동할 수 있다. 하지만 반드시 최단 경로로 이동해야 한다는 사실에 주의하라. 1번 정점에서 N번 정점으로 이동할 때, 주어진 두 정점을 반드시 거치면서 최단 경로로 이동하는 프로그램을 작성하시오.
입력
첫째 줄에 정점의 개수 N과 간선의 개수 E가 주어진다. (2 ≤ N ≤ 800, 0 ≤ E ≤ 200,000) 둘째 줄부터 E개의 줄에 걸쳐서 세 개의 정수 a, b, c가 주어지는데, a번 정점에서 b번 정점까지 양방향 길이 존재하며, 그 거리가 c라는 뜻이다. (1 ≤ c ≤ 1,000) 다음 줄에는 반드시 거쳐야 하는 두 개의 서로 다른 정점 번호가 주어진다.
출력
첫째 줄에 두 개의 정점을 지나는 최단 경로의 길이를 출력한다. 그러한 경로가 없을 때에는 -1을 출력한다.
예제 입력 1
4 6
1 2 3
2 3 3
3 4 1
1 3 5
2 4 5
1 4 4
2 3
예제 출력 1
7
나의 풀이
앞서 1753번 최단경로 문제에서 다익스트라 알고리즘을 사용해 특정 노드에서 다른 노드들로 가는 최단경로들을 구하는 문제를 풀었었다. 이 문제는 다익스트라 알고리즘을 사용해서 각 정점들의 최단경로들을 구한 뒤 경우의 수를 따져 최솟값을 구해주면 된다.
1번 노드에서 출발하여 N까지 가는데 거쳐야하는 두 노드를 v1, v2로 놓아보자. 그럼 이 두 노드를 거쳐 N까지 가는 경로는 두 가지의 경우의 수가 주어진다.
1 -> v1 -> v2 -> N
과1 -> v2 -> v1 -> N
이다. 따라서 이 두 가지 경우의 경로에서 최솟값들을 구해 이 중에서 작은 값이 곧 답이 된다.
그럼 이 두 가지의 최솟값은 어떻게 구하면 될까? 두 가지 중 한 가지인
1 -> v1 -> v2 -> N
을 예로들자면 1번에서 v1으로 가는 최솟값과 v1에서 v2로 가는 최솟값, v2에서 N으로 가는 최솟값을 더해주면 되지 않을까? 그럼 이 최솟값은 자연스럽게 다익스트라 알고리즘을 사용해서 구하면 된다는 생각을 할 수 있다. 따라서 1번에서 출발하는 다익스트라 알고리즘. v1에서 출발하는 다익스트라 알고리즘, v2에서 출발하는 다익스트라 알고리즘을 돌려 각 노드로 이동하는 최솟값을 담는 배열을 만들어놓고 위에서 말한 두 가지의 경우의 값을 계산하면 된다.
이 문제에서는 무방향그래프가 주어지므로 인접리스트를 만들때
1 2 3
이 주어진다면 1번과 2번 노드에 각각[2,3], [1,3]
을 넣어주어야 한다는 것도 주의해야한다.
코드
# 1504번 특정한 최단 경로
import sys, heapq
inf = float('inf')
# dijkstra
def dijkstra(start, g, n):
# 최소 비용 배열
d = [inf] * (n+1)
d[start] = 0
# 최소 힙
mheap = []
heapq.heappush(mheap, [0,start])
while mheap:
tmp = heapq.heappop(mheap)
cost = tmp[0]
node = tmp[1]
if cost > d[node]:
continue
for n in g[node]:
neighbor = n[0]
n_cost = d[node] + n[1]
if n_cost < d[neighbor]:
d[neighbor] = n_cost
heapq.heappush(mheap, [n_cost,neighbor])
return d
# mainㅌ
n, e = [int(x) for x in sys.stdin.readline().split()]
# 인접리스트
g = [[] for _ in range(n+1)]
for _ in range(e):
a, b, c = [int(x) for x in sys.stdin.readline().split()]
# 무방향 그래프로 양쪽 모두 추가
g[a].append([b,c])
g[b].append([a,c])
v1, v2 = [int(x) for x in sys.stdin.readline().split()]
d_start = dijkstra(1,g,n)
d_v1 = dijkstra(v1,g,n)
d_v2 = dijkstra(v2,g,n)
answer = min(d_start[v1] + d_v1[v2] + d_v2[n], d_start[v2] + d_v2[v1] + d_v1[n])
print(answer if answer != inf else -1)
'Programming > Algorithm' 카테고리의 다른 글
[백준1436번] 영화감독 숌 / Python3 (0) | 2020.03.25 |
---|---|
[백준9370번] 미확인 도착지 / Python3 (3) | 2020.03.17 |
[백준1753번] 최단경로 / Python3 (0) | 2020.03.15 |
[백준2206번] 벽 부수고 이동하기 / Python3 (0) | 2020.03.14 |
[백준1697번] 숨바꼭질 / Python3 (0) | 2020.03.13 |