오늘의 인기 글
최근 글
최근 댓글
Today
Total
05-19 08:40
관리 메뉴

우노

[Algorithm] 플로이드 워셜(Floyd-Warshall) 알고리즘이란? 본문

Algorithm/Concept

[Algorithm] 플로이드 워셜(Floyd-Warshall) 알고리즘이란?

운호(Noah) 2022. 7. 4. 20:16

플로이드 워셜(Floyd-Warshall) 알고리즘이란?

  • 플로이드 워셜 알고리즘은 ‘모든 지점에서 다른 모든 지점까지의 최단 경로를 모두 구해야 하는 경우'에 사용할 수 있는 알고리즘입니다.
  • 해당 알고리즘은 매 단계마다 ‘현재 노드를 거쳐 가는 노드'를 기준으로 알고리즘을 수행합니다.
    • 노드의 개수가 N개일 때, 알고리즘상으로 N번의 단계를 통해 현재 노드를 선택하며,
    • 단계마다 O(N^2)의 연산을 통해 ‘현재 노드를 거쳐 가는' 모든 경로를 고려합니다.
    • 따라서, 플로이드 워셜 알고리즘의 총 시간 복잡도는 O(N^3)입니다.
  • 해당 알고리즘은 2차원 리스트에 ‘최단 거리' 정보를 저장한다는 특징이 있습니다.
    • 모든 노드가 다른 모든 노드로 가는 최단 거리 정보를 담아야 하기 때문입니다.
  • 해당 알고리즘은 다이나믹 프로그래밍이라는 특징이 있습니다.
    • 노드의 개수가 N이라고 할 때, N번 만큼의 단계를 반복하며
    • ‘점화식에 맞게' 2차원 리스트를 갱신합니다.
  • 예제
    • 예를 들어, 현재 1번 노드를 선택했다면, 1번 노드를 중간에 거쳐 지나가는 모든 경우를 고려하게 됩니다.
    • 만약, 최단 거리 테이블에 A번 노드에서 B번 노드로 이동하는 비용이 3으로 기록되어 있을 때,
    • A번 노드에서 1번 노드를 거쳐 B번 노드로 이동하는 비용이 2라면,
    • A번 노드에서 B번 노드로 이동하는 비용을 2로 갱신하는 방식으로 진행됩니다.

점화식

  • D_ab = min(D_ab, D_ak + D_kb)

정리

  • 전체적으로 3중 반복문을 이용하며, 위의 점화식에 따라 최단 거리 테이블을 갱신하면 됩니다.
  • 위의 점화식은, ‘A에서 B로 가는 최소 비용'과 ‘A에서 K를 거쳐 B로 가는 비용'을 비교하여, 더 작은 값으로 갱신하겠다는 의미입니다.

중요

  • 초기 테이블 설정 시, ‘연결되지 않은 간선'에는 임의의 큰 값을 넣습니다.
  • 또한, 자기 자신으로 가는 비용은 모두 0으로 초기화합니다.
    • 왼쪽 위에서 오른쪽 아래로 내려가는 대각선
  • 마지막으로, 현재 노드가 포함된 행과 열은 업데이트되지 않습니다.
    • 예를 들어, 현재 노드로 1번 노드가 선택됐을 경우,
    • 업데이트 해야하는 값은, 1번 노드를 거쳐가는 간선이므로,
    • 2에서 1로 가는 간선 및 1에서 2로 가는 간선과 같이 직접 연결된 간선은 업데이트 되지 않습니다.

동작 과정 예제

예제 코드

INF = int(1e9) # 무한을 의미하는 값으로 10억을 설정

# 노드의 개수 및 간선의 개수를 입력받기
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):
        # 도달할 수 없는 경우, 무한(INFINITY)이라고 출력
        if graph[a][b] == 1e9:
            print("INFINITY", end=" ")
        # 도달할 수 있는 경우 거리를 출력
        else:
            print(graph[a][b], end=" ")
    print()

입력 및 출력 예시

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

참고

Comments