본문으로 바로가기

[Dijkstra] 1753번 최단경로

category Algorithm/BOJ 문제풀이 2018. 11. 22. 13:16
1753_최단 경로

1753번 최단경로 (다익스트라 알고리즘)

 

https://www.acmicpc.net/problem/1753


 

문제

방향그래프가 주어지면 주어진 시작점에서 다른 모든 정점으로의 최단 경로를 구하는 프로그램을 작성하시오. 단, 모든 간선의 가중치는 10 이하의 자연수이다.

 

입력

첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1≤V≤20,000, 1≤E≤300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다. 둘째 줄에는 시작 정점의 번호 K(1≤K≤V)가 주어진다. 셋째 줄부터 E개의 줄에 걸쳐 각 간선을 나타내는 세 개의 정수 (u, v, w)가 순서대로 주어진다. 이는 u에서 v로 가는 가중치 w인 간선이 존재한다는 뜻이다. u와 v는 서로 다르며 w는 10 이하의 자연수이다. 서로 다른 두 정점 사이에 여러 개의 간선이 존재할 수도 있음에 유의한다.

 

출력

첫째 줄부터 V개의 줄에 걸쳐, i번째 줄에 i번 정점으로의 최단 경로의 경로값을 출력한다. 시작점 자신은 0으로 출력하고, 경로가 존재하지 않는 경우에는 INF를 출력하면 된다.

 

예제 입력

5 6
1
5 1 1
1 2 2
1 3 3
2 3 4
2 4 5
3 4 6

 

예제 출력

0
2
3
7
INF

 

해결방법

 

💎 다익스트라 알고리즘(Dijkstra Algoritme) 💎

# 정의

: 하나의 정점에서 다른 모든 정점까지의 최단 경로를 구하는 방법 (Single Source ans Shortest Path Problem)

 

# Base Logic

: 첫 정점을 기준으로 연결되어 있는 정점을 추가해가며 최단 거리를 갱신함 (정점을 잇기 전까지는 모두 INF)

 

A → B 인 경우, Dist[B]는 아래의 2개 중 최소값을 저장한다

  • 시작점부터 A 까지의 최소 비용 + A → B 의 가중치
  • 기존에 가지고 있던 B 의 최소비용

 

참고 블로그

 


먼저 시작점은 E 이다

E 에서 갈 수 있는 경로는 BD 이다

먼저 D 노드를 보면, 현재 비용은 ∞ 이고, E를 거쳐 갈 수 있는 비용은 2 이다. 이 중 최소값은 2이다

B 노드의 경우, 현재 비용은 ∞ 이고, E를 거쳐 갈 수 있는 비용은 4 이다. 이 중 최소값은 4이다

이제 나머지 정점 중에서 가장 짧은 정점을 가지고 있는 D 를 고른다

D 노드에서 갈 수 있는 경로는 BC 이다

B 의 현재 비용은 4 이고, D 를 거치는 비용은 3 이다. 이 중 최소값은 3이다

C 노드의 경우 현재 비용은 ∞ 이고, D 를 거치는 비용은 3 이다. 이 중 최소값은 3이다

이런 식으로 진행 하다보면 최소 경로를 모두 구할 수 있다

 

 

💎 우선순위 큐(Priority Queue) 💎

# 정의

큐(Queue)와 비슷하지만 내부 구조는 완전히 다르다

top, pop에서 추출되는 원소는 제일 먼저 들어왔던 게 아닌, 현재 우선순위 큐 안에서 가장 우선순위가 높은 원소이다!!

 

# 구조

priority_queue<T, Container, Compare> pq;

 

# 사용법

insert(element);		// pq에 원소 추가
pop();				// pq에서 top의 원소를 삭제
top();				// top에 있는 원소를 반환

 

# 구현

- Max Heap

priority_queue<int, vector<int>,less<int>> pq;

 

- Min Heap

priority_queue<int, vector<int>,grater<int>> pq;

 

- Custom

typedef pair<int,int> node;

struct cmp {
    bool operator()(node x, node y){
        return x.second > y.second;
    }
};

priority_queue<node, vector<node>, cmp> pq;

 

소스코드

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#define MAX 20000
#define INF 987654321
using namespace std;

int n,m,s;        // n: 정점의 개수, m: 간선의 개수, s: 시작 정점
int u,v,w;        // u: 시작 정점, v: 도착 정점, w: 간선의 가중치

typedef pair<int, int> node;            // first: 정점, second: 정점의 최소 거리
struct cmp{
    bool operator()(node x, node y){
        return x.second > y.second;
    }
};

vector<vector<node>> adj;           // 간선을 나타내는 벡터

void dijkstra(){
    vector<int> dist(n+1, INF);     // 정점의 최소 거리
    priority_queue<node,vector<node>,cmp> pq;
    pq.push(make_pair(s, 0));
    dist[s] = 0;
    
    while(!pq.empty()){
        int pre_v = pq.top().first;     // 현재 정점
        int pre_d = pq.top().second;    // 현재 정점의 최소 거리
        pq.pop();
        
        if(pre_d > dist[pre_v]) continue;   // 
        
        for(int i=0; i<adj[pre_v].size(); i++){
            int nxt_v = adj[pre_v][i].first;   // 다음 정점
            int cost = adj[pre_v][i].second;   // 현재 정점 → 다음 정점의 가중치
            
            if(dist[nxt_v] > dist[pre_v] + cost){
                dist[nxt_v] = dist[pre_v] + cost;
                pq.push(make_pair(nxt_v, dist[nxt_v]));
            }
        }
    }
    
    for(int i=1; i<=n; i++){
        if(dist[i] == INF)
            cout << "INF" << endl;
        else
            cout << dist[i] << endl;
    }
}

int main(int argc, const char * argv[]) {
    // cin,cout 속도향상
    ios_base::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    
    cin >> n >> m;
    cin >> s;
    
    adj.resize(n+1);
    
    for(int i=0; i<m; i++){
        cin >> u >> v >> w;
        adj[u].push_back(make_pair(v, w));
    }
    
    dijkstra();
    
    return 0;
}


'Algorithm > BOJ 문제풀이' 카테고리의 다른 글

[Dijkstra] 1504번 특정한 최단 경로  (0) 2018.11.24
[Dijkstra] 1916번 최소비용 구하기  (0) 2018.11.22
[BF] 1644번 소수의 연속합  (0) 2018.11.21
[BF] 1806번 부분합  (0) 2018.11.21
[BF] 2003번 수들의 합2  (0) 2018.11.21