ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 다익스트라(Dijkstra) 알고리즘
    Programming/알고리즘 2020. 11. 16. 02:08

    다익스트라(Dijkstra) 알고리즘은 다니아닉 프로그래밍을 활용한 대표적인 최단 경로 탐색 알고리즘이다.

    다익스트라 알고리즘은 특정한 하나의 정점에서 다른 모든 정점으로 가는 최단 경로를 알려준다(이때 음의 간선은 포함될 수 없다). 현실세계에서는 음의 간선이 존재하지 않기 때문에 다익스트라 알고리즘은 현실 세계에서 적용하기에 매우 적합한 알고리즘이라고 할 수 있다.

     

    다익스트라 알고리즘이 다이나믹 프로그래밍 문제인 이유는 '최단 거리는 여러 개의 최단 거리로 이루어져있기 때문이다.' --> 현재까지 알고 있던 최단 경로를 계속해서 갱신한다!

     

    이번 게시물에서의 그래프 예시는 위와 같이 정했다. 먼저, 배열을 사용해서 다익스트라 알고리즘을 완성해보자.

     

    #include <iostream>
    
    using namespace std;
    
    int number = 6;
    int INF = 100000;
    int a[6][6] = {
    	{0, 2, 5, 1, INF, INF},
    	{2, 0 ,3, 2, INF, INF},
    	{5, 3, 0, 3, 1, 5},
    	{1, 2, 3, 0, 1, INF},
    	{INF, INF, 1, 1, 0, 2},
    	{INF, INF, 5, INF, 2, 0}	
    };
    
    int d[6];
    bool v[6];
    
    int getIndex() {
    	int min = INF;
    	int index = 0;
    	for (int i = 0; i < number; i++) {
    		if (d[i] < min && !v[i]) {
    			min = d[i];
    			index = i;
    		}
    	}
    	return index;
    }
    
    void dijkstra(int start) {
    	v[start] = true;
    	for (int i = 0; i < number; i++) {
    		d[i] = a[start][i];
    	}
    	for (int i = 0; i < number - 2; i++) {
    		int next = getIndex();
    		v[next] = true;
    		for (int j = 0; j < number; j++) {
    			if (d[j] > a[next][j] + d[next]) {
    				d[j] = a[next][j] + d[next];
    			}
    		}
    	}
    
    }
    
    int main() {
    	dijkstra(0);
    	for (int i = 0; i < number; i++) {
    		printf("%d ", d[i]);
    	}
    
    	return 0;
    }

     

    위와 같이 구현할 수 있으나 선형 탐색으로 구현하였기에 시간 복잡도가 O(n^2)이 된다. 하지만 우리는 힙 구조를 활용하여 시간 복잡도를 줄일 수 있다.

     

    #include <iostream>
    #include <vector>
    #include <queue>
    
    using namespace std;
    
    int number = 6;
    int INF = 100000;
    
    vector <pair<int, int>> a[7];
    int d[7];
    
    void dijkstra(int start) {
    	priority_queue<pair<int, int>> pq;
    	d[start] = 0;
    	pq.push(make_pair(0, start));
    
    	while (!pq.empty()) {
    		int current = pq.top().second; // priority_queue는 first부터 비교하기 때문에 vector a[]와 인덱스 순서가 다르다.
    		int distance = -pq.top().first; // priority_queue는 최대 힙 구조이기 때문에 꺼내고 집어넣을때 음수(-)처리를 해준다.
    		pq.pop();
    
    		for (int i = 0; i < a[current].size(); i++) { // 현재 노드에서 인접한 노드에 대해 for문을 돌린다.
    			int next = a[current][i].first;
    			int nextDistance = distance + a[current][i].second;
    			if (nextDistance < d[next]) {
    				d[next] = nextDistance;
    				pq.push(make_pair(-nextDistance, next));
    			}
    
    		}
    	}
    }
    
    int main() {
    	int edge = 0;
    	scanf("%d", &edge);
    
    	for (int i = 1; i <= number; i++) {
    		d[i] = INF;
    	}
    
    	for (int i = 0; i < edge; i++) {
    		int from, to, val = 0;
    		scanf("%d %d %d", &from, &to, &val);
    		a[from].push_back(make_pair(to, val));
    	}
    
    	dijkstra(1);
    
    	for (int i = 1; i <= number; i++) {
    		printf("%d ", d[i]);
    	}
    
    	return 0;
    }

    위 소스코드는 vector를 사용하여 시간 복잡도를 O((V+E)logV)까지 줄일 수 있다(V는 정점의 개수, E는 한 정점의 주변 노드의 개수).

    'Programming > 알고리즘' 카테고리의 다른 글

    위상 정렬(Topology sort)  (0) 2020.11.17
    플로이드 와샬 알고리즘  (0) 2020.11.16
    에라토스테네스의 체  (0) 2020.11.15
    다이나믹 프로그래밍 (Dynamic Programming)  (0) 2020.11.07
    이진 트리와 순회 방식  (0) 2020.11.07

    댓글

Designed by Tistory.