[백준 1753] 최단경로 (C#, C++) - soo:bak
작성일 :
문제 링크
설명
방향 그래프가 주어지는 상황에서, 정점의 개수 V (1 ≤ V ≤ 20,000)와 간선의 개수 E (1 ≤ E ≤ 300,000), 시작 정점 K, 그리고 각 간선의 정보(출발 정점, 도착 정점, 가중치 1~10)가 주어질 때, 시작 정점에서 모든 정점까지의 최단 경로를 구하는 문제입니다.
서로 다른 두 정점 사이에 여러 개의 간선이 존재할 수 있으며, 도달할 수 없는 정점에 대해서는 INF를 출력합니다.
접근법
모든 간선의 가중치가 양수이므로 다익스트라(Dijkstra) 알고리즘을 사용할 수 있습니다.
다익스트라 알고리즘은 시작 정점에서 각 정점까지의 최단 거리를 점진적으로 확정해 나가는 방법입니다.
기본 원리는 다음과 같습니다:
1. 초기화:
- 시작 정점의 거리는 0, 나머지 정점의 거리는 무한대로 설정합니다
- 우선순위 큐에 시작 정점을 넣습니다
2. 반복 처리:
- 우선순위 큐에서 현재까지 발견된 최단 거리가 가장 짧은 정점을 꺼냅니다
- 해당 정점을 통해 인접한 정점으로 가는 경로를 확인합니다
- 더 짧은 경로를 발견하면 거리를 갱신하고 우선순위 큐에 추가합니다
3. 최적화:
- 이미 확정된 정점(큐에서 꺼낸 거리가 현재 기록된 거리보다 큰 경우)은 건너뜁니다
- 우선순위 큐를 사용하여 항상 가장 짧은 거리의 정점을 먼저 처리합니다
예를 들어, 5개 정점과 시작 정점 1이 주어지고 간선이 다음과 같다면:
- 1 → 2 (가중치 2)
- 1 → 3 (가중치 3)
- 2 → 3 (가중치 1)
- 2 → 4 (가중치 5)
- 3 → 4 (가중치 2)
처리 과정:
- 초기: 거리 = [0, ∞, ∞, ∞, ∞] (정점 1~5)
- 정점 1 처리: 2까지 2, 3까지 3 → [0, 2, 3, ∞, ∞]
- 정점 2 처리: 3까지 2+1=3(갱신 안 됨), 4까지 2+5=7 → [0, 2, 3, 7, ∞]
- 정점 3 처리: 4까지 3+2=5(7→5로 갱신) → [0, 2, 3, 5, ∞]
- 정점 4 처리: 더 이상 갱신 없음
최종 최단 거리: 1번 0, 2번 2, 3번 3, 4번 5, 5번 INF
우선순위 큐를 사용하면 각 간선을 최대 한 번씩 확인하므로 시간 복잡도는 O((V + E) log V)입니다.
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
using System;
using System.Collections.Generic;
namespace Solution {
class Program {
static void Main(string[] args) {
var input = Array.ConvertAll(Console.ReadLine()!.Split(), int.Parse);
var v = input[0];
var e = input[1];
var k = int.Parse(Console.ReadLine()!);
var graph = new List<(int to, int weight)>[v + 1];
for (var i = 1; i <= v; i++)
graph[i] = new List<(int to, int weight)>();
for (var i = 0; i < e; i++) {
var edge = Array.ConvertAll(Console.ReadLine()!.Split(), int.Parse);
graph[edge[0]].Add((edge[1], edge[2]));
}
const int INF = int.MaxValue;
var dist = new int[v + 1];
Array.Fill(dist, INF);
dist[k] = 0;
var pq = new PriorityQueue<(int vertex, int distance), int>();
pq.Enqueue((k, 0), 0);
while (pq.Count > 0) {
var (vertex, distance) = pq.Dequeue();
if (distance > dist[vertex]) continue;
foreach (var (next, weight) in graph[vertex]) {
var newDist = distance + weight;
if (newDist < dist[next]) {
dist[next] = newDist;
pq.Enqueue((next, newDist), newDist);
}
}
}
for (var i = 1; i <= v; i++)
Console.WriteLine(dist[i] == INF ? "INF" : dist[i].ToString());
}
}
}
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
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
typedef vector<vector<pii>> vvpii;
typedef vector<int> vi;
typedef priority_queue<pii, vector<pii>, greater<pii>> min_pq;
const int INF = INT_MAX;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int v, e, k; cin >> v >> e >> k;
vvpii graph(v + 1);
for (int i = 0; i < e; i++) {
int u, to, weight; cin >> u >> to >> weight;
graph[u].push_back({to, weight});
}
vi dist(v + 1, INF);
dist[k] = 0;
min_pq pq;
pq.push({0, k});
while (!pq.empty()) {
auto [distance, vertex] = pq.top();
pq.pop();
if (distance > dist[vertex]) continue;
for (auto [next, weight] : graph[vertex]) {
int newDist = distance + weight;
if (newDist < dist[next]) {
dist[next] = newDist;
pq.push({newDist, next});
}
}
}
for (int i = 1; i <= v; i++) {
if (dist[i] == INF) cout << "INF\n";
else cout << dist[i] << "\n";
}
return 0;
}