BumCode

Dijkstra's algorithm

다익스트라 알고리즘은 하나의 정점 에서 다른 모든 정점으로 가는 최단 경로 탐색 알고리즘이다.
알고리즘에 대한 자세한 설명은 건너뛰고 구현위주로 작성하겠다.

  • 벡터
  • 배열
  • 우선순위 큐

C++로 다익스트라 구현하기 위해 위 3가지가 필요하다.

우선 정점의 개수가 N개라고 가정을 하자.

벡터는 다음과 같이 선언할 것이다. (1번 정점부터 N번 정점까지 저장해야하기에 N+1)

vector<pair<int, int>> vertex[N+1];

vertex[i] : i번 정점
vertex[i]의 원소 :pair( i에서 갈 수 있는 다른 정점 , 그 정점까지의 가중치 )

예를 들어 다음 그래프에서 vertex[1]과 vertex[2]의 원소는 다음과 같다.
graph

방향성이 없는 그래프이므로 서로에 대한 정보를 가진다.
vertex[1][0] = (2,3)
vertex[2][0] = (1,3)

다음으로 선언해줄 것은 최단거리를 저장할 배열이다.

INF(무한)로 초기화를 해준다.

int D[N+1];
for(int i=1;i<=N;i++)D[i]=INF;

마지막으로 우선순위 큐 priority_queue가 필요하다.(#include <queue>)

우선순위 큐는 큐와 다르게 원소 중 값이 가장 큰 값을 가장 먼저 빼준다.
다익스트라에서는 값이 가장 작은 순으로 꺼내야하기에 거리에 -를 해주어 큐에 넣을 것이다.

priority_queue<pair<int, int>> PQ;

이제 구현해보자.

시작 정점 v1을 인자로 넣어주면 v1에서 다른 모든 정점으로의 최단 거리를 배열에 저장해 주는 함수를 구현할 것이다.

//#include <bits/stdc++.h>
#include <vector>
#include <queue>
#define INF 2'100'000'000
vector<pair<int, int>> vertex[N+1];
int D[N+1]; //배열은 INF로 초기화된 상태

void dijkstra(int v1)
{
    priority_queue<pair<int, int>> PQ;

    //시작정점 v1에서 v1까지의 거리는 0이므로
    PQ.push(make_pair(0,v1));
    D[v1]=0;

    //큐가 비어질 때까지 반복한다.
    while(!PQ.empty())
    {
        //v1에서 지금 보고있는 정점까지의 비용
        int Cost = -PQ.top().first;

        //지금 보고있는 정점
        int Ver = PQ.top().second;
        PQ.pop();

        //큐에서 꺼낸, 지금 보고있는 정점까지의 거리가 현재 저장된 최단거리보다 큰경우
        //꺼낸 거리에서 다른 정점으로 가는 건 최단거리가 아니기에 패스한다.
        if(Cost>D[Ver]) continue;

        //지금 보고있는 정점에서 갈 수 있는 다른 모든 정점까지의 거리를 보기위해 반복
        for(int i=0;i<vertex[Ver].size();i++)
        {
            //Ver에서 갈 수 있는 정점
            int nextVer = vertex[Ver][i].first;

            //Ver에서 nextVer까지의 거리
            int nextCost = vertex[Ver][i].second;

            //Ver에서 nextVer로 가는 거리가 현재 저장된 최단거리보다 작으면
            if(D[Ver]+nextCost < D[nextVer])
            {
                //최단경로를 갱신해준다.
                D[nextVer] = D[Ver]+nextCost;

                //갱신되었으므로 우선순위 큐에 넣어줌
                PQ.push(-D[nextVer], nextVer);
            }
        }
    }
}

위 함수가 실행되면 D[i]에는 v1에서 i까지의 최단거리가 저장되고 경로가 없는 경우 INF가 그대로 유지된다.

각 정점까지의 경로를 알고싶다면?

정점개수크기의 배열 int path[N+1]을 선언해주고 최단경로가 갱신될 때마다 path[nextVer]에 Ver를 저장해주면 된다.

함수가 끝난 뒤, path[i]에는 i까지 최단거리로 이동할 때 i이전의 정점이 저장되기에 추적해주면 된다.

방향성이 있는 그래프에서 모든 정점에서 K번 정점까지의 거리를 알고싶다면?

모든 정점에서 각각 다익스트라를 돌려서 즉, N번 돌려서 구할 수 있다.

하지만 한번으로 구하는 것이 가능하다.

그래프의 방향을 반전시켜 K에서 다익스트라를 구하면 된다!!