# [BOJ] 1504 특정한 최단 경로 - python
그래프, 최단 경로 문제, 다익스트라 알고리즘
# 문제 요약
- Given:
- 무방향성 가중 그래프(Undirected weighted graph)
- 반드시 거쳐야 하는, 두개의 정점 번호(v1, v2)
- Constraints:
- 2 <= N(정점의 개수) <= 800
- 0 <= E(간선의 개수) <= 200,000
- 1 <= c(가중치) <= 1,000
- v1 != v2, v1 != N, v2 != 1
- Problem:
- 아래의 두가지 조건을 만족하면서, 1번 정점 에서 N번 정점 으로 이동하는 특정한 최단 경로를 구해라.
- 조건1. 임의로 주어진 두 정점은 반드시 통과해야 한다.
- 조건2. 이미 방문한 정점, 이미 거쳤던 간선도 다시 이동할 수 있다.
- 아래의 두가지 조건을 만족하면서, 1번 정점 에서 N번 정점 으로 이동하는 특정한 최단 경로를 구해라.
# 문제 접근 플로우
- (문제 제목에서 알 수 있다시피)최단 경로 알고리즘을 사용하는 문제다. 따라서 다익스트라 알고리즘을 활용하여, 문제 해결할 수 있을 것으로 보인다.
- 최단 경로는 반드시 1번 정점 에서 출발하여 N번 정점 에서 끝난다. 따라서 최단 경로는 아래와 같은 형태이다
- 최단경로(1~>N) : path: 1 -> .... -> N
- v1, v2 을 반드시 거쳐야한다. 따라서 최단 경로는 min(path1, path2) 일것
- path1 : 1 -> ...-> v1 -> ...-> v2 -> ... -> N
- path2 : 1 -> ...-> v2 -> ...-> v1 -> ... -> N
- 중복 방문(or 이동)이 가능하다는 조건 덕분에, path1 과 path2 는 다음과 같이 분할 가능하다. 따라서, 전형적인 최단경로 문제로 변형되었다.
- path1: 최단경로(1~>v1) + 최단경로(v1~>v2) + 최단경로(v2~>N)
- path2: 최단경로(1~>v2) + 최단경로(v2~>v1) + 최단경로(v1~>N)
- 예외(경로가 없는 경우)
- 1~>v1 경로가 없는 경우
- 1~>v2 경로가 없는 경우
- 1~>N 경로가 없는 경우
# 구현
- 다익스트라(dijkstra) 함수를 세번 호출하여, 부분 경로의 최단 경로를 구한다. 그다음 부분 경로를 합하여 path1 과 path2 의 최단 경로 길이를 구한다. 최종적으로 path1 과 path2 중에 짧은 길이를 최단 경로 길이로 결정한다.
- 그래프 표현: 인접 행렬(Adjaacency matrix)로 정점 연결 관계 및 간선 가중치 표현
- if adj[u][v] == 1404: 연결x
- else : 연결o
- 다익스트라 구현 : 전형적인 다익스트라 구현과 같음
from sys import stdin
import heapq
input = stdin.readline
def solve(V, E, adj, v1, v2):
def dijkstra(src):
dist = [float('inf') for _ in range(V)]
dist[src] = 0
pq = []
heapq.heappush(pq, (dist[src], src))
while pq:
cost, here = heapq.heappop(pq)
if dist[here] < cost:
continue
for there in range(V):
weight = adj[here][there]
if weight == 1404:
continue
next_dist = cost + weight
if dist[there] > next_dist:
dist[there] = next_dist
heapq.heappush(pq, (next_dist, there))
return dist
dist_to = dijkstra(0)
if float('inf') in (dist_to[v1], dist_to[v2], dist_to[V - 1]):
return -1
path1 = dist_to[v1] # 0 -> v1
path2 = dist_to[v2] # 0 -> v2
dist_to = dijkstra(v1)
path1 += dist_to[v2] # v1 -> v2
path2 += dist_to[V - 1] # v1 -> V-1
dist_to = dijkstra(v2)
path1 += dist_to[V - 1] # path1 : 0->v1->v2->V-1
path2 += dist_to[v1] # path2 : 0->v2->v1->V-1
return min(path1, path2)
def main():
V, E = map(int, input().split())
adj = [[1404 for _ in range(V)] for _ in range(V)]
for _ in range(E):
a, b, c = map(int, input().split())
if c < adj[a - 1][b - 1]:
adj[a - 1][b - 1] = adj[b - 1][a - 1] = c
v1, v2 = [int(x) - 1 for x in input().split()]
res = solve(V, E, adj, v1, v2)
print(res)
main()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
Tags:
problemsolving
python