다익스트라(dijkstra) 알고리즘이란?
다익스트라 알고리즘이란?
다익스트라 알고리즘은 그래프에서 하나의 정점을 기준으로 다른점과의 최단거리를 구할때 유용한 알고리즘입니다. 시험에서도 유도과정을 구하는 문제로 나오는 단골문제이기도 하죠. 간단히 정리하면 아래와 같습니다.
- 하나의 정점을 기준으로 다른점들과의 최단거리를 구할때 쓴다.
- O(n*logn)의 시간 복잡도를 가진다.
- 거리가 음수가 아닐때 사용할 수 있다.
- 아직 가지 못하거나 못가는 곳은 INF로 표시된다.
예시
아래와 같은 그래프에서 최단거리를 탐색한다고 가정하자.
0인 노드에서부터 시작하여 0과 다른 노드간의 최단거리를 구할 것이다.
먼저 1 vs 7 노드로 가는길 중 1이 4로 더 작기 때문에 4노드를 탐색한다.
그 후 7노드로 가는 비용이 제일 작으므로 7선택
6 노드 선택
이런 식으로 뻗어나갈때 최소비용으로 뻗어나갈 수 있는 노드를 선택하면서 갱신해준다.
이러한 과정을 표로 표현하면 이렇게 된다.
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0 | INF | INF | INF | INF | INF | INF | INF | INF |
0 | 4 | INF | INF | INF | INF | INF | INF | INF |
0 | 4 | INF | INF | INF | INF | INF | 8 | INF |
0 | 4 | INF | INF | INF | INF | 9 | 8 | INF |
0 | 4 | INF | INF | INF | 11 | 9 | 8 | INF |
0 | 4 | 12 | INF | INF | 11 | 9 | 8 | INF |
0 | 4 | 12 | INF | INF | 11 | 9 | 8 | 14 |
0 | 4 | 12 | 19 | INF | 11 | 9 | 8 | 14 |
0 | 4 | 12 | 19 | 21 | 11 | 9 | 8 | 14 |
설명
- 모든 정점과의 거리를 INF 초기화하고, 정점 0부터 출발한다.
- 이어져 있는 노드 중 최소 비용인것을 선택한다.
- 고른 노드를 통해 최솟값인 경우 갱신해주고 후보에 삽입해준다.
- 모든 노드를 탐색할때까지 반복한다.
소스코드
O(n^2)인 소스
#include <iostream>
using namespace std;
const int V = 9;
const int INF = 1e9;
// 방문하지 않은 정점 중 가장 비용이 작은 정점을 구하는 함수
int minDistance(int dist[], bool sptSet[]) {
int min = INF, min_index;
for (int v = 0; v < V; ++v) {
if (!sptSet[v] && dist[v] <= min) {
min = dist[v], min_index = v;
}
}
return min_index;
}
// 다익스트라를 통해 구한 한 정점에서 각 정점까지의 거리를 출력하는 함수
void printSolution(int dist[]) {
cout << "Vertex \t\t Distance from Source\n";
for (int i = 0; i < V; ++i)
cout << i << " \t\t " << dist[i] << '\n';
}
// 한 정점에서 다른 정점과의 최단거리를 구하는 함수
void dijkstra(int graph[V][V], int src) {
int dist[V]; // 최단거리를 담는 배열
bool sptSet[V]; // 해당 정점이 최단거리인지 알려주는 배열
// 모든 정점과의 거리를 INF로 초기화
for (int i = 0; i < V; ++i) {
dist[i] = INF, sptSet[i] = false;
}
// 시작 정점은 자신과의 거리 0
dist[src] = 0;
for (int count = 0; count < V - 1; ++count) {
// 최소 정점을 골라줌
int u = minDistance(dist, sptSet);
sptSet[u] = true;
// 해당 정점에서 다른 정점으로 가는 값이 기존의 값보다 작으면 갱신해줌
for (int v = 0; v < V; ++v) {
if (!sptSet[v] && graph[u][v] && dist[u] != INF
&& dist[u] + graph[u][v] < dist[v])
dist[v] = dist[u] + graph[u][v];
}
}
printSolution(dist);
}
int main() {
int graph[V][V] = { { 0, 4, 0, 0, 0, 0, 0, 8, 0 },
{ 4, 0, 8, 0, 0, 0, 0, 11, 0 },
{ 0, 8, 0, 7, 0, 4, 0, 0, 2 },
{ 0, 0, 7, 0, 9, 14, 0, 0, 0 },
{ 0, 0, 0, 9, 0, 10, 0, 0, 0 },
{ 0, 0, 4, 14, 10, 0, 2, 0, 0 },
{ 0, 0, 0, 0, 0, 2, 0, 1, 6 },
{ 8, 11, 0, 0, 0, 0, 1, 0, 7 },
{ 0, 0, 2, 0, 0, 0, 6, 7, 0 } };
dijkstra(graph, 0);
return 0;
}
priority_queue를 이용하여 O(nlogn)인 소스
minDistance 함수를 priority_queue로 대체 했을뿐 그 외 다른건 없다.
#include <iostream>
#include <queue>
using namespace std;
const int V = 9;
const int INF = 1e9;
struct vertex {
int index, distance;
// 거리 작은 순으로 정렬
bool operator < (const vertex& v) const {
return this->distance > v.distance;
}
};
// 다익스트라를 통해 구한 한 정점에서 각 정점까지의 거리를 출력하는 함수
void printSolution(int dist[]) {
cout << "Vertex \t\t Distance from Source\n";
for (int i = 0; i < V; ++i)
cout << i << " \t\t " << dist[i] << '\n';
}
// 한 정점에서 다른 정점과의 최단거리를 구하는 함수
void dijkstra(int graph[V][V], int src) {
int dist[V]; // 최단거리를 담는 배열
bool sptSet[V]; // 해당 정점이 최단거리인지 알려주는 배열
priority_queue<vertex> pq; // 최단거리 순으로 반환하는 최소힙
// 모든 정점과의 거리를 INF로 초기화
for (int i = 0; i < V; ++i) {
dist[i] = INF, sptSet[i] = false;
}
// 시작 정점은 자신과의 거리 0
dist[src] = 0;
pq.push({ src, 0 });
while (!pq.empty()) {
int u = pq.top().index;
pq.pop();
sptSet[u] = true;
for (int v = 0; v < V; ++v) {
if (!sptSet[v] && graph[u][v] && dist[u] != INF
&& dist[u] + graph[u][v] < dist[v]) {
dist[v] = dist[u] + graph[u][v];
pq.push({ v, dist[v] });
}
}
}
printSolution(dist);
}
int main() {
int graph[V][V] = { { 0, 4, 0, 0, 0, 0, 0, 8, 0 },
{ 4, 0, 8, 0, 0, 0, 0, 11, 0 },
{ 0, 8, 0, 7, 0, 4, 0, 0, 2 },
{ 0, 0, 7, 0, 9, 14, 0, 0, 0 },
{ 0, 0, 0, 9, 0, 10, 0, 0, 0 },
{ 0, 0, 4, 14, 10, 0, 2, 0, 0 },
{ 0, 0, 0, 0, 0, 2, 0, 1, 6 },
{ 8, 11, 0, 0, 0, 0, 1, 0, 7 },
{ 0, 0, 2, 0, 0, 0, 6, 7, 0 } };
dijkstra(graph, 0);
return 0;
}
댓글남기기