[백준 1504] 특정한 최단 경로 (C#, C++) - soo:bak
작성일 :
문제 링크
설명
무방향 가중치 그래프가 주어지는 상황에서, N개의 정점 (2 ≤ N ≤ 800), E개의 간선 (0 ≤ E ≤ 200,000), 그리고 반드시 거쳐야 하는 두 정점 v1, v2가 주어질 때, 1번 정점에서 N번 정점까지 v1과 v2를 모두 거쳐서 가는 최단 경로의 길이를 구하는 문제입니다.
가능한 경로는 1 → v1 → v2 → N 또는 1 → v2 → v1 → N 두 가지입니다. 경로가 존재하지 않으면 -1을 출력합니다.
접근법
다익스트라를 세 번 실행하여 필요한 모든 구간의 최단 거리를 구합니다.
먼저 1번, v1, v2에서 각각 다익스트라를 실행합니다. 1번에서 시작한 다익스트라로 1 → v1과 1 → v2 거리를 얻고, v1에서 시작한 다익스트라로 v1 → v2와 v1 → N 거리를, v2에서 시작한 다익스트라로 v2 → N 거리를 얻습니다.
두 가지 경로의 비용을 계산합니다. 첫 번째 경로는 1 → v1 + v1 → v2 + v2 → N이고, 두 번째 경로는 1 → v2 + v2 → v1 + v1 → N입니다.
이렇게 계산한 두 경로 중 더 짧은 것을 선택합니다. 어느 구간이라도 도달 불가능하면 -1을 출력합니다.
시간 복잡도는 O(E log N)입니다.
Code
C#
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
63
64
65
66
67
68
69
70
using System;
using System.Collections.Generic;
namespace Solution {
class Program {
const int INF = int.MaxValue / 4;
static List<(int to, int w)>[] adj = Array.Empty<List<(int, int)>>();
static int[] Dijkstra(int start, int n) {
var dist = new int[n + 1];
Array.Fill(dist, INF);
dist[start] = 0;
var pq = new PriorityQueue<int, int>();
pq.Enqueue(start, 0);
while (pq.Count > 0) {
pq.TryDequeue(out var cur, out var d);
if (d > dist[cur])
continue;
foreach (var edge in adj[cur]) {
var nxt = edge.to;
var w = edge.w;
var nd = dist[cur] + w;
if (nd < dist[nxt]) {
dist[nxt] = nd;
pq.Enqueue(nxt, nd);
}
}
}
return dist;
}
static void Main(string[] args) {
var first = Array.ConvertAll(Console.ReadLine()!.Split(), int.Parse);
var n = first[0];
var e = first[1];
adj = new List<(int, int)>[n + 1];
for (var i = 1; i <= n; i++)
adj[i] = new List<(int, int)>();
for (var i = 0; i < e; i++) {
var parts = Array.ConvertAll(Console.ReadLine()!.Split(), int.Parse);
var a = parts[0];
var b = parts[1];
var c = parts[2];
adj[a].Add((b, c));
adj[b].Add((a, c));
}
var last = Array.ConvertAll(Console.ReadLine()!.Split(), int.Parse);
var v1 = last[0];
var v2 = last[1];
var distFrom1 = Dijkstra(1, n);
var distFromV1 = Dijkstra(v1, n);
var distFromV2 = Dijkstra(v2, n);
var path1 = (long)distFrom1[v1] + distFromV1[v2] + distFromV2[n];
var path2 = (long)distFrom1[v2] + distFromV2[v1] + distFromV1[n];
var ans = Math.Min(path1, path2);
if (distFromV1[v2] >= INF || ans >= INF)
Console.WriteLine(-1);
else
Console.WriteLine(ans);
}
}
}
C++
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
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vp;
typedef vector<vp> vvp;
const int INF = 1e9;
vvp adj;
vi dijkstra(int start, int n) {
vi dist(n + 1, INF);
priority_queue<pii, vp, greater<pii>> pq;
dist[start] = 0;
pq.push({0, start});
while (!pq.empty()) {
auto [d, u] = pq.top();
pq.pop();
if (d > dist[u])
continue;
for (auto [v, w] : adj[u]) {
if (dist[v] > dist[u] + w) {
dist[v] = dist[u] + w;
pq.push({dist[v], v});
}
}
}
return dist;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, e; cin >> n >> e;
adj.assign(n + 1, {});
for (int i = 0; i < e; i++) {
int a, b, c; cin >> a >> b >> c;
adj[a].push_back({b, c});
adj[b].push_back({a, c});
}
int v1, v2; cin >> v1 >> v2;
auto d1 = dijkstra(1, n);
auto dv1 = dijkstra(v1, n);
auto dv2 = dijkstra(v2, n);
ll path1 = (ll)d1[v1] + dv1[v2] + dv2[n];
ll path2 = (ll)d1[v2] + dv2[v1] + dv1[n];
ll ans = min(path1, path2);
if (dv1[v2] >= INF || ans >= INF)
cout << -1 << "\n";
else
cout << ans << "\n";
return 0;
}