-
플로이드 워셜 알고리즘Algorithms in Python/notes 2021. 2. 14. 16:06
플로이드 워셜(Floyd-Warshall) 알고리즘
모든 지점에서 다른 모든 지점까지의 최단 경로를 모두 구해야 하는 경우 사용할 수 있는 알고리즘
• 노드의 개수를 N이라고 할 때, N번 만큼의 단계를 반복하며 '점화식에 맞게' 2차원 리스트를 갱신한다.
• 각 단계에서는 해당 노드를 거쳐가는 경우를 고려한다.
ex) 1번노드를 확인할 때는 1번 노드를 중간에 거쳐 지나가는 모든 경우를 고려한다.
- A -> 1번 노드 -> B 의 비용 확인 후 최단거리 갱신
=> 현재 확인하고 있는 노드를 제외하고, N - 1개의 노드 중에서 서로 다른 노드 (A, B) 쌍을 선택한다. 이후에 A -> 1번 노드 -> B로 가는 비용을 확인한 후에 최단 거리를 갱신한다. 다시말해 N-1P2개의 쌍을 단계마다 반복해서 확인한다.
• K번의 단계에 대한 점화식 : Dab = min(Dab, Dak + Dkb)
• 따라서 전체 시간 복잡도는 O(N3)이다. O(N-1P2)는 O(N2)
다익스트라 VS 플로이드 워셜
• 단계마다 최단 거리를 가지는 노드를 하나씩 반복적으로 선택하고 해당노드를 거쳐가는 경로를 확인하여 최단 거리 테이블을 갱신해가는 방식이다.
• 1차원 리스트
• 그리디 알고리즘• 매번 방문하지 않은 노드 중에서 최단 거리를 갖는 노드를 찾을 필요가 없다.
• 2차원 리스트
• 다이나믹 프로그래밍플로이드 워셜 알고리즘 예시
초기 테이블 설정
• 연결된 간선 : 그 값, 연결되지 않은 간선 : 무한
출발/도찰 1번 2번 3번 4번 1번 0 4 INF 6 2번 3 0 7 INF 3번 5 INF 0 4 4번 INF INF 2 0 ① 1번노드를 거쳐가는 경우를 고려한다.
=> 1번 노드를 거쳐 갈 때가 더 빠른 경우가 존재한다면 빠른 경우로 최단 거리를 갱신해주는 식이다.
3P2 = 6가지 경우만 생각하면 된다.
D23 = min(D23, D21 + D13)
D24 = min(D24, D21 + D14)
D32 = min(D32, D31 + D12)
D34 = min(D34, D31 + D14)
D42 = min(D42, D41 + D12)
D43 = min(D43, D21 + D13)
출발/도찰 1번 2번 3번 4번 1번 0 4 INF 6 2번 3 0 7 9 3번 5 9 0 4 4번 INF INF 2 0 ② 2번노드를 거쳐가는 경우를 고려한다.
출발/도찰 1번 2번 3번 4번 1번 0 4 11 6 2번 3 0 7 9 3번 5 9 0 4 4번 INF INF 2 0 ③ 3번노드를 거쳐가는 경우를 고려한다.
출발/도찰 1번 2번 3번 4번 1번 0 4 11 6 2번 3 0 7 9 3번 5 9 0 4 4번 7 11 2 0 ④ 4번노드를 거쳐가는 경우를 고려한다.
출발/도찰 1번 2번 3번 4번 1번 0 4 8 6 2번 3 0 7 9 3번 5 9 0 4 4번 7 11 2 0 최종 결과
출발/도찰 1번 2번 3번 4번 1번 0 4 8 6 2번 3 0 7 9 3번 5 9 0 4 4번 7 11 2 0 플로이드 워셜 알고리즘 소스코드
INF = int(1e9) # 노드의 개수 및 간선의 개수를 입력받기 n = int(input()) m = int(input()) # 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): # 도달할 수 없는 경우 무한이라고 출력 if graph[a][b] == INF: print("INFINITY", end=' ') # 도달 할 수 있는 경우 거리를 출력 else: print(graph[a][b], end=' ') print()
* 이것이 코딩테스트다 with 파이썬 - 나동빈
'Algorithms in Python > notes' 카테고리의 다른 글
벨만 포드 알고리즘 (0) 2021.02.15 다익스트라 최단 경로 알고리즘 (0) 2021.02.10 위상 정렬 (0) 2021.02.07 크루스칼 알고리즘 (0) 2021.02.07 Union-Find 알고리즘 (0) 2021.02.07