개념/알고리즘
플로이드 워셜(Floyd Warshall)
34suuuuu
2024. 12. 11. 13:04
다익스트라는 한 지점에서 다른 지점으로의 최단 경로를 구하는 알고리즘이다.
하지만, 모든 지점에서 다른 모든 지점까지의 최단 경로를 모두 구해야하는 겨우에는 플로이드 워셜 알고리즘을 이용한다.
두 알고리즘의 차이점을 확인해보면 아래와 같다.
다익스트라의 경우에는
- 단계마다 최단 거리를 가지는 노드를 하나씩 반복적으로 선택
- 해당 노드를 거쳐가는 경로를 확인하며 테이블을 갱신
- 한 지점에서 다른 지점에 대한 최단 거리이기 때문에 1차원 배열
- 모든 지점에 대해 반복하면 확인하기 때문에 그리디 알고리즘
플로이드 워셜의 경우에는
- 방문하는 노드에 대해서만 최단 거리를 확인
- 모든 지점에서 모든 지점이기 때문에 2차원 배열
- 노드의 갯수만큼 방문하며 확인하기 때문에 dp 알고리즘
- 시간 복잡도 `O(n^3)`
🔻 그림으로 확인
[0] 최단 거리 행렬 초기화
초기 그래프를 인접 행렬로 나타내면 아래와 같다.
`INF`는 해당 노드에서 특정 노드까지의 경로가 존재하지 않는 경우이다.
0 | 5 | INF | 8 |
7 | 0 | 9 | INF |
2 | INF | 0 | 4 |
INF | INF | 3 | 0 |
[1] 1번 노드를 거쳐가는 경우
색칠한 부분만 갱신해주면 되는데
이 상황에서 `i`에서 `j`로 가는 최소 거리라는 것은
`i에서 1로 가는 비용 + 1에서 j로 가는 비용` 과 `i에서 j로 가는 최소 비용`을 비교하는 것이다.
이를 그래프와 코드로 나타내면 아래와 같다.
0 | 5 | INF | 8 |
7 | 0 | 9 | 15 |
2 | 7 | 0 | 4 |
INF | INF | 3 | 0 |
[2] 2번 노드를 거쳐가는 경우
0 | 5 | 14 | 8 |
7 | 0 | 9 | 15 |
2 | 7 | 0 | 4 |
INF | INF | 3 | 0 |
[3] 3번 노드를 거쳐가는 경우
0 | 5 | 14 | 8 |
7 | 0 | 9 | 15 |
2 | INF | 0 | 4 |
5 | 10 | 3 | 0 |
[4] 4번 노드를 거쳐가는 경우
0 | 5 | 11 | 8 |
7 | 0 | 9 | 15 |
2 | 7 | 0 | 4 |
5 | 10 | 3 | 0 |
🔻 전체 코드 (java)
최단 거리 행렬 초기화
시작 지점과 도착 지점이 같은 경우 즉, 자기 자신으로 가는 경로의 경우에는 `0`
아직 최단 거리가 존재하지 않는 경우에는 `INF`
최단 거리를 확인한 경우에는 해당 값을 입력한다.
for(int i = 1; i<=n; i++){
for(int j =1; j<=n; j++){
if (i == j) dist[i][j] = 0;
else if (adj[i][j]) dist[i][j] = adj[i][j];
else dist[i][j] = INF;
}
}
for문을 통한 행렬 갱신
중간 노드가 될 노드를 가장 바깥 for문의 변수로 지정한다.
i와 j를 통해 모든 노드를 확인하며 k를 중간 노드로 설정할 때와 아닐 때의 값을 비교해 최단 거리로 갱신한다.
for(int k = 1; k<= n; k++){
for(int i = 1; i <= n; i++){
for(int j = 1; j<=n; j++){
dist[i][j] = Math.min(dist[i][j], dist[i][k]+dist[k][j]);
}
}
}