백준 No.1504 [특정한 최단 경로]
본문 바로가기
Algorithm (C++ based)/BOJ

백준 No.1504 [특정한 최단 경로]

by 조훈이 2021. 2. 9.

Baekjoon Online Judge No.1504 [특정한 최단 경로]


 Problem

 

1504번: 특정한 최단 경로

첫째 줄에 정점의 개수 N과 간선의 개수 E가 주어진다. (2 ≤ N ≤ 800, 0 ≤ E ≤ 200,000) 둘째 줄부터 E개의 줄에 걸쳐서 세 개의 정수 a, b, c가 주어지는데, a번 정점에서 b번 정점까지 양방향 길이 존

www.acmicpc.net


   Code   

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
71
72
73
74
75
#include <iostream>
#include <vector>
#include <queue>
#define dist first
#define vertex second
 
using namespace std;
typedef pair<intint> PII;
 
const int INF = 2100000000;
int V, E;
vector<vector<PII>> node;
 
int solve(int vertex_start, int vertex_target) {
    vector<int> dist_to(V + 1-1); // dist_to[i] == distance between vertex_start and i
    priority_queue<PII, vector<PII>, greater<PII>> pq;
    // first = dist, second = vertex : defined at line #4, #5
 
    dist_to[vertex_start] = 0;
    pq.push(PII(dist_to[vertex_start], vertex_start));
 
    while (!pq.empty()) {
        int curVer = pq.top().vertex;
        int curCost = pq.top().dist;
 
        pq.pop();
 
        if (curCost > dist_to[curVer]) continue;
 
        for (int i = 0; i < node[curVer].size(); i++) {
            int nextVer = node[curVer][i].vertex;
            int nextCost = curCost + node[curVer][i].dist;
 
            if (dist_to[nextVer] == -1 || dist_to[nextVer] > nextCost) {
                dist_to[nextVer] = nextCost;
                pq.push(PII(nextCost, nextVer));
            }
        }
    }
 
    return dist_to[vertex_target];
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
 
    cin >> V >> E;
 
    node.resize(V + 1);
 
    for (int i = 0; i < E; i++) {
        int s, e, v;
        cin >> s >> e >> v;
 
        node[s].push_back(PII(v, e));
        node[e].push_back(PII(v, s));
    }
 
    int visit1, visit2;
    cin >> visit1 >> visit2;
 
    int s_to_v1 = solve(1, visit1);
    int s_to_v2 = solve(1, visit2);
 
    int between_v = solve(visit1, visit2);
 
    int v1_to_e = solve(visit2, V);
    int v2_to_e = solve(visit1, V);
    
    if (s_to_v1 != -1 && s_to_v2 != -1 && between_v != -1 && v1_to_e != -1 && v2_to_e != -1)
        cout << between_v + min(s_to_v1 + v1_to_e, s_to_v2 + v2_to_e);
    else cout << -1;
}
cs

   How to solve   

  제일 일반적인 Dijkstra문제(2021/02/08 - [C++ Algorithm/Dijkstra] - Dijkstra (다익스트라))에서 살짝 변형을 하면 풀 수 있었다.

 

  • 양방향 간선이므로 #58처럼 e 정점에서 v 정점으로 가는 node도 추가를 해 주었다.

양방향 간선

  첫 번째 경유지를 visit1, 두 번째 경유지를 visit2라고 할 때 두 가지 경우가 나온다.

 

  • Start vertex (s) ----------> visit1 ----------> visit2 ----------> End vertex (e)
  • Start vertex (s) ----------> visit2 ----------> visit1 ----------> End vertex (e)

이 두 경우중 더 작은 거리를 가지는 경우가 정답이 된다.

  기본적인 Dijkstra 에선 시작 정점에 대한 정보로 모든 정점들에 대한 최소 거리를 구했는데 Dijkstra를 구하는 함수에 (#14 line) 시작정점과 끝정점에 대한 정보를 주고, 입력된 시작정점부터 끝정점까지 가는 최소 거리를 return하도록 했다.

 

  위 코드에선 요구한 data들의 범위나 개수가 그렇게 많지 않아서 Dijkstra를 구하는 solve(...)를 그때그때 선언하여 했지만 Memoization을 해놓고 사용해도 좋을 것 같다. 만약 이 방법을 사용한다면, 시작점으로 주어질 경우들에 대해서만 미리 MEmoization을 해놓으면 될 것이다.

 

  만약 #64 ~ #70 의 변수들 중 단 하나라도 '-1'의 값을 가지는 변수가 있다면, 이 말은 즉슨 가고자 하는 어느 두 정점 사이 가는 방법이 없다는 말 이므로 '-1'을 출력했다.

 

  BFS에서도 단방향, 양방향에 대한 개념을 알 수 있지만 이 문제에서 또한 그래프의 단방향, 양방향에 대한 개념을 조금 익혀갈 수 있는 것 같다. 

  

728x90

'Algorithm (C++ based) > BOJ' 카테고리의 다른 글

백준 No.13913 [숨바꼭질4]  (0) 2021.02.16
백준 No.13549 [숨바꼭질3]  (0) 2021.02.16
백준 No.11066 [파일 합치기]  (0) 2021.02.07
백준 No.12865 [평범한 배낭]  (0) 2021.02.06
백준 No.10942 [팰린드롬?]  (0) 2021.02.05

댓글