티스토리 뷰
1. 문제 링크
11779번: 최소비용 구하기 2
첫째 줄에 도시의 개수 n(1≤n≤1,000)이 주어지고 둘째 줄에는 버스의 개수 m(1≤m≤100,000)이 주어진다. 그리고 셋째 줄부터 m+2줄까지 다음과 같은 버스의 정보가 주어진다. 먼저 처음에는 그 버스
www.acmicpc.net
2. 문제 개요
간선이 주어지고 출발지, 도착지의 정점 번호가 주어질 때, 출발지, 도착지까지의 최단거리, 경로를 구하는 프로그램을 작성하시오.
3. 문제 힌트
(1) 인접 리스트로 나타낼 것. -> 한 정점에서 다른 정점까지의 간선이 1개라면 행렬로 나타내어도 괜찮다. 그런데 한 정점에서 다른 정점까지 간선이 여러 개 있을 수 있으니 인접 리스트로 나타내어야 한다.
그 외 특별히 주의할 점은 없다.
n이 최대 1000이라 O(n^2) dijkstra알고리즘을 써도 될 것 같지만 이왕 문제 푸는 거 우선순위 큐를 사용해보자.
4. 문제 풀이
맞은사람이 많아서 풀이를 안 하려고 했다. 다른 더 똑똑하신 분들이 이미 잘 써놓으셨을 거라고 생각했기 때문. 그런데 문제가 너무 전형적이고, formal 하다고 해야 할까.. 꼭 알아야만 할 것 같아서 복습, 메모도 할 겸.. 업로드를 합니다.
풀이라고 해야 할까, 특별한 트릭이 없다.
최단 거리를 못 찾는 것은 인접 행렬에서 우선순위 큐로 자료구조를 변경했을 때 아직 알고리즘 내부에서 어떤 부분이 어떻게 바뀌었는지를 이해하지 못하기 때문이라고 생각한다.
최단 경로를 못 찾는 이유는 dijkstra알고리즘 그 자체의 원리를 한번 더 공부할 필요가 있다고 생각한다. 언제 값이 갱신되고, 갱신할 때 어떤 값을 어떻게 저장하면 경로를 저장할 수 있는지...
(원리에 대해서는 다른 블로그에 더 훌륭하신 분들이 정리하신 내용이 이미 많으니 생략하겠습니다.^_^)
간단히..
인접 행렬이랑 우선순위 큐의 차이점은 이때까지 최단경로를 찾은 정점들의 집합에 연결된 모든 정점들에 대해서 어떻게 최솟값을 찾을 건지에 달려있습니다.
인접 행렬 같은 경우는 O(n), 즉 처음부터 끝까지 순회하면서 최솟값을 찾고, 우선순위 큐는 힙 정렬을 통해 O(logn)만에 최솟값을 찾습니다.
우선순위 큐에는 최단경로일 것 같은 후보 정점들을 큐에 넣어 최솟값을 구하기 때문에 조건에 만족하지 않는 후보들을 제거하기 위해 while문의 시작 부분에 continue부분이 있어야 합니다.
5. 코드
#include <cstdio> #include <queue> #include <vector> using namespace std; struct ITEM { ITEM() {} ITEM(int dist_, int cur_) :dist(dist_),cur(cur_){} int dist, cur; bool operator<( const ITEM &other)const { return this->dist < other.dist; } }; const int INF = 987654321; int n, m; vector<vector<pair<int, int>>> adj; //next, weight vector<int> parent,dist, path; priority_queue<ITEM> pq; int dep, ari; //departure, arrival int main() { scanf("%d", &n); scanf("%d", &m); adj.resize(n + 1); //for [0,n] parent.resize(n + 1); dist.resize(n + 1, INF); // I dont have any information about shortest distance -> INF for (int i = 0; i < m; ++i) { int from, to, weight; scanf("%d %d %d", &from, &to, &weight); adj[from].push_back({ to,weight }); } scanf("%d %d", &dep, &ari); dist[dep] = 0; pq.push(ITEM(dist[dep],dep)); while (!pq.empty()) { ITEM item = pq.top(); pq.pop(); if (dist[item.cur] < item.dist) continue; //remove unnecessary candidates //compare all vertices that are connected to item.cur to get the shorest path for (pair<int, int> e : adj[item.cur]) { int next = e.first; int weight = e.second; if (dist[next] > dist[item.cur] + weight) { dist[next] = dist[item.cur] + weight; //update parent[next] = item.cur; //for path....tracing pq.push(ITEM(dist[next], next)); // next vertex is a candidate so far of shortest path, } } } for (int v = ari; v != 0; v = parent[v]) path.push_back(v); //it acts like the 'stack' printf("%d\n%d\n",dist[ari], path.size()); for (int i = path.size() - 1; i >= 0; --i) printf("%d ", path[i]); return 0; }
6. 결과

'알고리즘 > Dijkstra' 카테고리의 다른 글
boj, 백준) 5719. 거의 최단 경로( C / C++ ) (0) | 2021.01.19 |
---|---|
boj, 백준) 10217. KCM travel ( C / C++) (0) | 2020.11.16 |
백준, boj ) 2211. 네트워크 복구 ( C++) (0) | 2020.06.16 |