[알고리즘] 플로이드 워셜 알고리즘

Sujin Lee·2022년 5월 16일
0

알고리즘

목록 보기
3/12
post-thumbnail
post-custom-banner

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

  • '모든 지점에서 다른 모든 지점까지의 최단 경로를 모두 구해야 하는 경우' 사용할 수 있는 알고리즘
  • 다익스트라 알고리즘과 마찬가지로 단계별로 거쳐 가는 노드를 기준으로 알고리즘을 수행
    • 다만, 매 단계마다 방문하지 않은 노드 중에 최단 거리를 갖는 노드를 찾는 과정이 필요하지 않다.
  • 2차원 리스트에 '최단 거리'정보를 저장
  • 다이나믹 프로그래밍(DP) 유형에 속함
    • 노드의 개수가 N이라고 할 때, N번 만큼의 단계를 반복하며 점화식에 맞게 2차원 리스트를 갱신하기 때문에
  • 현재 확인하고 있는 노드를 제외하고, N-1개의 노드 중에서 서로 다른 노드 (A,B) 쌍을 선택한다. 이후에 A -> 1번 노드 -> B로 가는 비용을 확인한 뒤에 최단 거리를 갱신한다. 다시 말해 N1P2_{N-1}P_2개의 쌍을 단계마다 반복해서 확인하면 된다.
  • 이때 O(N1P2)O(_{N-1}P_2)O(N2)O(N^2)라고 볼 수 있기 때문에, 전체 시간 복잡도는 O(N3)O(N^3)이라고 할 수 있다.
  • 구체적인 (K번의 단계에 대한) 점화식
    • Dab=min(Dab,Dak+Dkb)D_{ab} = min(D_{ab}, D_{ak}+ D_{kb})
    • A에서 B로 가는 최소 비용A에서 K를 거쳐 B로 가는 비용을 비교하여 더 작은 값으로 갱신하겠다!
    • 바로 이동하는 거리특정한 노드를 거쳐서 이동하는 거리보다 더 많은 비용을 가진다면 이를 더 짧은 것으로 갱신한다는 것

동작 과정

플로이드 워셜 알고리즘: 동작 과정 살펴보기
[초기 상태] 그래프를 준비하고 최단 거리 테이블을 초기화한다.

  • 연결된 간선은 단순히 그 값을 채워 넣고, 연결되지 않은 간선은 '무한'이라는 값을 넣는다.
  • 자기 자신에서 자기 자신으로 가는 비용은 0이므로, DiiD_{ii}(1 ≤ i ≤ n)는 0으로 초기화

[Step 1] 1번 노드를 거쳐 가는 경우를 고려하여 테이블을 갱신한다

  • 예를 들어, D23=min(D23,D21+D13)D_{23} = min(D_{23}, D_{21}+ D_{13})
  • 기존의 2번 노드에서 3번 노드로 가는 비용 보다 2번 노드에서 1번을 거쳐 3번 노드로 가는 비용이 더 작다면, 그것으로 갱신해주겠다.

[Step 2] 2번 노드를 거쳐 가는 경우를 고려하여 테이블을 갱신한다

[Step 3] 3번 노드를 거쳐 가는 경우를 고려하여 테이블을 갱신한다

[Step 4] 4번 노드를 거쳐 가는 경우를 고려하여 테이블을 갱신한다

  • 노드의 갯수가 4개이므로 총 [Step 4]까지 알고리즘 수행

소스코드

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()
profile
공부한 내용을 기록하는 공간입니다. 📝
post-custom-banner

0개의 댓글