플로이드 워셜 최단 거리 알고리즘
- 모든 노드에서 다른 모든 노드까지의 최단 경로를 모두 계산한다
- 플로이드 워셜(Floyd-Warshall) 알고리즘은 다익스트라 알고리즘과 마찬가지로 단계별로 거쳐 가는 노드를 기준으로 알고리즘을 수행한다
- 다만 매 단계마다 방문하지 않은 노드 중에 최단 거리를 갖는 노드를 찾는 과정이 필요하지 않다
- 플로이드 워셜은 2차원 테이블에 최단 거리 정보를 저장한다
- 플로이드 워셜 알고리즘은 다이나믹 프로그래밍 유형에 속한다
- 각 단계마다 특정한 노드 𝑘를 거쳐 가는 경우를 확인한다
- 𝑎에서 𝑏로 가는 최단 거리보다 𝑎에서 𝑘를 거쳐 𝑏로 가는 거리가 더 짧은지 검사한다
- 시간 복잡도는 → 번의 단계 마다 의 연산을 통해 현재 거쳐가는 모든 경로 고려
점화식은 다음과 같다.
✔ 플로이드 워셜 알고리즘 동작 과정
[초기 상태] 그래프를 준비하고 최단 거리 테이블을 초기화
- 연결된 간선은 단순히 그 값을 채워 넣고, 연결 되지 않은 간선은 무한 값을 넣습니다.
Step 1 1번 노드를 거쳐 가는 경우를 고려하여 테이블을 갱신한다
$D_{ab}$ : a에서 b로 가는 최소 비용
a→b 의 최소 비용은 a에서 b로 바로 가는 비용과 k를 거쳐서, 즉 a→k→b의 비용 중 작은 값이다.
⭐ 점화식 : $D_{ab} = min(D_{ab} , D_{a1} + D_{1b})$
$D_{23} = min(D_{23} , D_{21} + D_{13})$
$D_{24} = min(D_{24} , D_{21} + D_{14})$
$D_{32} = min(D_{32} , D_{31} + D_{12})$
$D_{34} = min(D_{34} , D_{31} + D_{14})$
$D_{42} = min(D_{42} , D_{41} + D_{12})$
$D_{43} = min(D_{43} , D_{41} + D_{13})$
1을 거쳐 갈 때가 더 빠른 경우가 존재한다면 빠른 경우로 최단 거리를 갱신하는 식
Step 2 2번 노드를 거쳐 가는 경우를 고려하여 테이블을 갱신한다
⭐ 점화식 : $D_{ab} = min(D_{ab} , D_{a2} + D_{2b})$
$D_{13} = min(D_{13} , D_{12} + D_{23})$
$D_{14} = min(D_{14} , D_{12} + D_{24})$
$D_{31} = min(D_{31} , D_{32} + D_{22})$
$D_{34} = min(D_{34} , D_{32} + D_{24})$
$D_{41} = min(D_{41} , D_{42} + D_{22})$
$D_{43} = min(D_{43} , D_{42} + D_{23})$
2번 노드를 거쳐 가는 경우, 2번 노드를 제외한 1번, 3번, 4번 노드에서 2개의 노드를 뽑는 경우를 고려한다.
Step 3 3번 노드를 거쳐 가는 경우를 고려하여 테이블을 갱신한다
⭐ 점화식 : $D_{ab} = min(D_{ab} , D_{a3} + D_{3b})$
$D_{12} = min(D_{12} , D_{13} + D_{32})$
$D_{14} = min(D_{14} , D_{13} + D_{34})$
$D_{21} = min(D_{21} , D_{23} + D_{31})$
$D_{24} = min(D_{24} , D_{23} + D_{34})$
$D_{41} = min(D_{41} , D_{43} + D_{31})$
$D_{42} = min(D_{42} , D_{43} + D_{32})$
3번을 제외하고 1번, 2번, 4번 중에서 두 쌍을 선택하는 경우는 (1,2), (1,4), (2,1), (2,4), (4,1), (4,2) 로 6가지 경우가 있다.
갱신되는 식에 대하여 $_3P_2 = 6$ 에 대한 수식이 만들어 지게 되며, 결국 $_{N-1}P_{2}$ 개의 쌍을 단계마다 반복해서 확인하고 있다.
Step 4 4번 노드를 거쳐 가는 경우를 고려하여 테이블을 갱신한다
⭐ 점화식 : $D_{ab} = min(D_{ab} , D_{a4} + D_{4b})$
$D_{12} = min(D_{12} , D_{14} + D_{42})$
$D_{13} = min(D_{13} , D_{14} + D_{43})$
$D_{21} = min(D_{21} , D_{24} + D_{41})$
$D_{23} = min(D_{23} , D_{24} + D_{43})$
$D_{31} = min(D_{31} , D_{34} + D_{41})$
$D_{32} = min(D_{32} , D_{34} + D_{42})$
[최종 결과]
✔ 구현
입력예시
4
7
1 2 4
1 4 6
2 1 3
2 3 7
3 1 5
3 4 4
4 3 2
출력예시
0 4 8 6
3 0 7 9
5 9 0 4
7 11 2 0
첫번째, 두번째의 n,m 은 노드의 개수와 간선의 개수
세 번째 줄 부터는 시작 노드 , 도착 노드 , 소모 거리
INF = int(1e9) # 무한을 의미하는 값으로 10억을 설정
n, m = map(int, input().split()) #노드 개수, 간선 개수
# 2차원 리스트(그래프 표현)를 만들고, 모든 값을 무한으로 초기화
graph = [[INF] * (n + 1) for _ in range(n + 1)]
# 자기 자신에서 자기 자신으로 가는 비용은 0으로 초기화
for a in range(1, n + 1):
for b in range(1, n + 1):
if a == b:
graph[a][b] = 0
# 각 간선에 대한 정보를 입력 받아, 그 값으로 초기화
for _ in range(m):
# A에서 B로 가는 비용은 C라고 설정
a, b, c = map(int, input().split())
graph[a][b] = c
# 점화식에 따라 플로이드 워셜 알고리즘을 수행
for k in range(1, n + 1):
for a in range(1, n + 1):
for b in range(1, n + 1):
graph[a][b] = min(graph[a][b], graph[a][k] + graph[k][b])
# 수행된 결과를 출력
for a in range(1, n + 1):
for b in range(1, n + 1):
# 도달할 수 없는 경우, 무한(INFINITY)이라고 출력
if graph[a][b] == 1e9:
print("INFINITY", end=" ")
# 도달할 수 있는 경우 거리를 출력
else:
print(graph[a][b], end=" ")
print()
'알고리즘 > 기타 알고리즘' 카테고리의 다른 글
[그리디 Greedy] 문자열 뒤집기 (0) | 2022.01.24 |
---|---|
[그리디 Greedy] 모험가 길드 (0) | 2022.01.24 |
재귀함수 Recursion Funtion (0) | 2022.01.24 |
최단 경로 (Shortest Path Problem) : 다익스트라 알고리즘 (0) | 2022.01.24 |
[이것이 코딩 테스트다 with Python] 개미 전사 : Dynamic Programming (0) | 2022.01.24 |