백준 1753 - 최단경로
1 minute read
문제링크
문제설명
- 방향 그래프가 주어질 때 주어진 시작점에서 다른 모든 정점으로의 최단 경로를 구하는 프로그램을 작성하라.
- 정점의 개수는 2만개, 간선의 개수는 30만개로 시간초과와 메모리초과에 유의해야 한다.
문제접근
- 문제에서 주어지는 최대 정점의 개수, 간선의 개수를 고려했을 때 인접행렬을 사용하는 경우 메모리 초과에 걸린다. 따라서, 인접리스트를 이용해 최대 30만개의 데이터만 담을 수 있도록 한다.
- 최단경로 알고리즘은 여러가지가 있지만, 이 문제의 경우 음의 가중치가 없는 그래프의 한 정점에서 모든 정점까지의 최단거리 를 구하는 알고리즘이므로 다익스트라 알고리즘 이 적절한 방법이다.
- 로직은 다음과 같다.
- 인접리스트 형태로 그래프 정보를 담는 테이블을 만든다.
- vector<pair<int, int» table[u] 의 형태를 가지며, v -> table[u][i].first, w -> table[u][i].second 를 의미한다. 즉, u->v 로 가는 가중치 w를 입력으로 들어온 순서대로 담는다.
- 처음 모든 노드로의 최단 거리는 INF 로 설정한다.
- 시작점의 최단 거리는 0 이다.
- 우선순위 큐로 최소 힙을 구성하여 노드를 이동할 때 비용이 최소인 노드들부터 선택할 수 있도록 한다.
- 우선순위 큐에서 pair<int, int> 를 사용하는 경우 첫번째 인자를 정렬의 우선순위로 본다.
- 비용이 작은 순서대로 방문하기 때문에 기존에 방문하는데 필요한 비용보다 특정한 노드를 거쳐서 방문하는 비용이 더 큰 경우는 다른 경로를 탐색할 필요가 없다.
- 특정 노드를 통해 목표 노드를 방문했을 때, 이전에 필요했던 비용보다 적다면 최소 비용을 갱신한다.
구현
#include <iostream>
#include <vector>
#include <queue>
#define INF 9e8
using namespace std;
vector<pair<int, int>> table[20001];
// 우선순위 큐는 첫번째 인자를 우선적으로 비교하여 정렬함
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
int dist[20001];
int V, E;
void dijkstra(int start) {
pq.push(make_pair(0, start)); // (w, v) 순서로 올 것
dist[start] = 0;
while (!pq.empty()) {
int u = pq.top().second;
int w = pq.top().first;
pq.pop();
for (int i = 0; i < table[u].size(); i++) {
int v = table[u][i].first;
int x = table[u][i].second;
if (dist[v] > w + x) {
dist[v] = w + x;
pq.push(make_pair(w+x, v));
}
}
}
}
int main()
{
int K;
cin.tie(NULL);
ios_base::sync_with_stdio(false);
scanf("%d %d", &V, &E);
scanf("%d", &K);
int u, v, w;
for (int i = 0; i < E; i++) {
scanf("%d %d %d", &u, &v, &w);
table[u].push_back(make_pair(v, w));
}
// init
for (int v = 1; v <= V; v++) {
dist[v] = INF;
}
dijkstra(K);
for (int v = 1; v <= V; v++) {
if (dist[v] == INF) printf("INF\n");
else printf("%d\n", dist[v]);
}
}
Leave a comment