본문 바로가기

프로그래밍/알고리즘

최단 경로 (3)

Shortest Path (3)


Floyd-Warshall Algorithm

- all-to-all 최단 경로 알고리즘들 중 가장 유명하다.

- Floyd 알고리즘은 동적 계획법(Dynamic Programming) 전략에 기반하고 있다.

- 가중치 방향 그래프 G = (V, E) (V = {1, 2, ... , n})

- 모든 노드 쌍들간 최단 경로의 길이를 구한다.

- $d^k$[i, j]

중간에 노드 집합 {1, 2, ... , k}에 속한 노드들만 거쳐서 노드 i에서 j까지 가는 최단 경로의 길이를 뜻한다.

1) $d^0$[i, j]는 k가 0인 경우로 공집합을 의미한다. 또한 중간에 지날 수 있는 노드가 없다는 것으로 직접 연결된 엣지가 있지 않다면 길이를 ∞로 생각한다.

2) $d^n$[i, j]는 k가 n인 경우다. 이는 곧 아무 노드나 지나도 상관이 없다는 것과 같기 때문에 i에서 j까지 가는 최단 경로와 같다고 할 수 있으며 또한 알고리즘의 최종 목표이기도 하다.

3) $d^k$[i, j]는 1~k사이의 노드만 지날 수 있게 허용한 경우이다. 이 때는 두 가지 케이스가 존재하는데 k를 지나 목적지 j에 도달하는 경우와 그렇지 않은 경우이다.

4) k를 지나지 않는 경우 $d^{k-1}$[i,j]가 되며, k를 지날 경우 k이전까지의 노드들과 k이후 j까지의 노드들을 더한 $d^{k-1}$[i, k] + $d^{k-1}$[k, j]가 된다. $d^k$[i, j]는 두 경우 중 더 길이가 작은 경우를 선택하기만 하면 된다.

- 슈도 코드

FloydWarshall (G)

for i = 1 to n

for j = 1 to n

$d^0$[i, j] = $w_{ij}$;

for k = 1 to n // 반복을 계속하면 최종적으로 $d^n$[i, j]에 도달하게 된다.

for i = 1 to n

for j = 1 to n

//실제로 구현을 위해서는 d[k][i][j]와 같이 삼차원 배열을 사용해야 한다.

$d^k$[i, j] = min{$d^{k-1}$[i, j], $d^{k-1}$[i, k] + $d^{k-1}$[k, j]};

-> 위 코드는 삼중 반복문에 의해 O($n^3$)의 시간 복잡도를 가진다.

-> 다익스트라 또한 모든 노드에 대해 전부 알고리즘을 실행하면 O($n^3$)의 시간이 걸린다.

- 개선된 슈도 코드

위 코드와 같으나 $d^k$등 삼차원 배열 부분인 k를 제거하고 d로만 표시하여 이차원 배열로 만들어준다.

기존 가장 작았던 길이의 값들을 보존하기 위해 추가적으로 k를 사용할 것 없이 더 작은 값이 있으면 기존 값에 덮어씌우기만 하면 되기 때문에 삼차원일 필요는 없게 된다.

FloydWarshall (G)

for i = 1 to n

for j = 1 to n

$d^0$[i, j] = $w_{ij}$; // 최단 길이를 저장하는 배열

π[i, j] = null; // 최단 경로를 찾기 위한 배열

for k = 1 to n // 반복을 계속하면 최종적으로 $d^n$[i, j]에 도달하게 된다.

for i = 1 to n

for j = 1 to n

if d[i, j] > d[i, k] + d[k, j]

d[i, j] = min{d[i, j], d[i, k] + d[k, j]};

π[i, j] = k;

//s에서 t까지 가는 경로가 존재한다는 가정 하에 최단 경로상 중간노드들(s, t자신들은 제외)을 출력한다.

Print-Path (s, t, π)

if π[s, t] == null

return;

Print-path(s, π[s, t]);

print(π[s, t]);

Print-path(π[s, t], t);


'프로그래밍 > 알고리즘' 카테고리의 다른 글

압축 (2)  (0) 2019.06.23
압축 (1)  (0) 2019.06.23
최단 경로 (2)  (0) 2019.06.22
최단 경로 (1)  (0) 2019.06.20
최소 비용 신장 트리 (2)  (0) 2019.06.13