[알고리즘 정리] 다익스트라

3 분 소요

다익스트라는 음의 가중치가 없는 그래프의 한 정점에서 모든 정점까지의 최단거리를 각각 구하는 알고리즘입니다.

밑의 그림을 보며 다익스트라 알고리즘에 대하여 알아보겠습니다.

http://dl.dropbox.com/s/br6ozbjj35hgl3e/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-1.png

시작점 1을 기준으로, 다른 모든 정점으로 가는 최단 거리는 아래의 표와 같습니다.

http://dl.dropbox.com/s/owpvc15hnw9uj3z/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-2.png

한 정점에서 다른 정점으로 가는 경로는 여러가지로 표현될 수 있습니다.

예를 들어, 정점 1에서 정점 4로 가는 경로는 다음과 같은 두 가지 경우가 있습니다.

  • 1 → 2 → 4 : 비용 3
  • 1 → 4 : 비용 5

따라서 최단 거리를 구하기 위해서는 비용 5가 소모되는 경로가 아닌, 비용 3이 소모되는 경로를 선택해야 합니다.

각 정점으로의 최단 거리는 눈으로 바로 구할 수 있지만, 코드를 사용하면서 더 짧은 거리의 경로를 선택하기 위해서는 각 단계마다 값을 저장해주어야 합니다.

각 정점으로의 최단 거리를 보관하기 위한 1차원 배열이 필요 합니다. 또한 이 배열은 충분히 큰 값으로 초기화 되어야 합니다. 그 이유는, 이동 거리를 비교했을 때 더 작은 값을 선택하기 위함입니다.

가중치 배열을 초기화한 후의 동작 과정은 아래와 같습니다. 순차적으로 값을 갱신시켜 나아가기 위해 큐를 사용합니다.

  1. 큐의 맨 앞 요소를 꺼내와 출발지 정점을 선택합니다.
    • 만약, 해당 정점을 방문했다면, 아래 작업들을 건너 뛰고, 다시 1부터 시작합니다.
  2. 해당 출발지 정점까지의 최단 거리에 목적지 정점까지의 가중치를 더한 값(1)과, 기존에 구했던 목적지 정점까지의 최단 거리 값(2)을 비교합니다.
    • 만약, (1)이 (2)보다 더 작다면, 해당 거리를 (1)로 변경시켜주고,
    • 큐에 삽입합니다.
  3. 1, 2를 반복합니다.

위의 그래프와 동작 과정을 따라 최단 거리를 구해보겠습니다.

시작 정점 1에서 다시 시작점으로는 갈 수 없으니, 해당 거리는 0으로 설정합니다.

http://dl.dropbox.com/s/scqx3v5vqlaaqj4/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-3.png

큐에 삽입된 시작 정점과 해당 정점까지의 최단 거리 정보를 꺼내옵니다. 정점 1을 방문 처리 합니다.

시작 정점 1에서 갈 수 있는(=이어져 있고, 아직 방문하지 않음) 정점들로는 정점 2, 3, 4가 있습니다.

http://dl.dropbox.com/s/yk3y1if0jnk3tcm/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-4.png

  • 정점 1까지 이동했던 최단 거리(dist[1])인 0과, 목적지 정점 2까지의 가중치인 2를 더한 값인 2
  • 정점 2까지 이동했던 최단 거리(dist[2])인 INF

위의 두 값을 비교합니다.

초기에 갈 수 없다고 표시한 infinity 값보다 작으므로 최단 거리를 변경합니다.

갈 수 있는 또 다른 두 정점(3, 4)들도 위 과정을 거칩니다.

따라서 정점 2, 3, 4로의 최단 거리는 각각 2, 3, 5로 변경됩니다.

http://dl.dropbox.com/s/1kweefwotiqyif7/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-5.png

큐에는 정점 1과 연결된 정점 2, 3, 4로 가는 간선 정보가 들어 있습니다.

http://dl.dropbox.com/s/3pwt7cl18t819j9/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-6.png

다음으로, 우선 순위 큐에 따라 정렬되어 있는 요소들 중 최단거리 값이 가장 작은 맨 앞의 요소를 꺼내옵니다. 정점 2를 방문 처리 합니다.

정점 2를 기준으로 갈 수 있는 정점을 살펴 봅니다. 정점 4로 갈 수 있으며, 그 가중치는 1이 됩니다.

http://dl.dropbox.com/s/6wnv4p8lo9zldx8/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-7.png

  • 정점 2까지 이동했던 최단 거리(dist[2])인 2와, 목적지 정점 4까지의 가중치인 1을 더한 값인 3
  • 정점 4까지 이동했던 최단 거리(dist[4])인 5

두 값을 비교합니다.

정점 4로 바로 가는 경로보다, 정점 2를 들러서 가는 경로의 비용이 더 적으므로, 해당 값을 변경시켜 줍니다.

http://dl.dropbox.com/s/j2fh0yzicx7d0c9/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-8.png

큐에 새로 삽입된 간선 정보를 통해 정점 4로 가는 최단 거리가 5에서 3으로 변경되었음을 알 수 있습니다.

http://dl.dropbox.com/s/rhxot8u6dep7o3v/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-9.png

다음으로 우선 순위 큐 맨 앞 요소를 꺼냅니다. 정점 3을 방문 처리 합니다.

http://dl.dropbox.com/s/3l5awrutr709fu5/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-10.png

정점 3에서 갈 수 있는 정점들은 없으므로, 최단 거리를 갱신하는 과정을 생략합니다.

이제 큐에는 아래의 두 간선 정보만이 존재합니다.

http://dl.dropbox.com/s/95dma35t3w58yec/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-11.png

우선 순위 큐의 맨 앞 요소를 꺼내와, 해당 정점을 기준으로 갈 수 있는 정점들을 살펴봅니다. 정점 4를 방문 처리 합니다.

아래 그림을 살펴보면, 정점 4로부터 정점 3으로 비용 3을 소모해 갈 수 있는 것을 알 수 있습니다.

http://dl.dropbox.com/s/mte643lnt5vs6hp/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-12.png

그러면,

  • 정점 4까지 이동했던 최단 거리(dist[4])인 3과, 목적지 정점 3까지의 가중치인 4를 더한 값인 7
  • 정점 3까지 이동했던 최단 거리(dist[3])인 3

두 값을 비교합니다.

기존의 경로의 거리가 더 작으므로, 값은 변동이 없습니다.

http://dl.dropbox.com/s/tizbvy0kvaouk2z/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-13.png

큐에 있는 마지막 요소를 꺼내옵니다. 정점 4는 이미 방문한 기록이 있습니다.

방문한 기록이 있다는 것은, 그 정점까지로의 최단 거리를 이용하여 더 짧은 거리를 구하는 작업을 이미 했다는 것을 의미합니다. 따라서, 거리 비교하는 과정을 생략합니다.

http://dl.dropbox.com/s/9jqfsbqx92utgl4/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-14.png

큐가 비어있게 되면, 최단 거리를 구하는 과정이 모두 끝났음을 의미합니다. 계속 더 작은 값으로 갱신시켜 준 dist 배열의 각각의 요소가 해당 정점으로 가는 가장 짧은 거리가 됩니다. 만약 목적지 정점으로의 경로가 존재하지 않는다면, 초기화에 사용된 infinity 값이 남아있게 됩니다.

http://dl.dropbox.com/s/qsj5ckswxhljabg/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%20%EC%A0%95%EB%A6%AC-%EB%8B%A4%EC%9D%B5%EC%8A%A4%ED%8A%B8%EB%9D%BC-15.png

최악의 경우, 모든 간선 정보들을 우선 순위 큐에 넣게 되므로, O(ElogV)의 시간 복잡도를 가집니다.

카테고리:

업데이트:

댓글남기기