[Algorithm] 최단 경로 알고리즘 - 플로이드 워셜 알고리즘

곽호택·2021년 12월 20일
0

알고리즘

목록 보기
9/9
post-thumbnail
post-custom-banner

!"이것이 코딩 테스트다 with 파이썬" 책을 통해 공부한 내용을 정리하는 중이다. 저번 시간에는 다익스트라 알고리즘에 대해 공부했었는데 우선순위 큐를 통해서 구현하는 과정을 배웠다. 오늘은 그에 이어서 플로이드 워셜 알고리즘에 대해 공부하고 구현하는 것을 정리할 계획이다.

1. 플로이드 워셜 알고리즘

모든 지점에서 다른 모든 지점까지의 최단 경로를 모두 구해야 하는 경우에 사용

단계마다 '거쳐 가는 노드'를 기준으로 알고리즘을 수행!

노드의 개수가 N개일 때 N번의 단계를 수행하고, 단계마다 O(N^2)의 연사을 통해 '현재 노드를 거쳐 가는' 모든 경로를 고려한다.

즉 O(N^3)의 시간 복잡도를 가진다.

다익스트라 알고리즘이 1차원 리스트를 이용했다면, 플로이드 워셜 알고리즘은 2차원 리스트를 이용한다.

플로이드 워셜 알고리즘은 앞서 배웠던 다이나믹 프로그래밍인데 이는 노드의 개수가 N개일 때, N번 만큼의 단계를 반복하고 다음의 '점화식에 맞게' 2차원 리스트를 갱신하기 때문이다.

Dab = min(Dab, Dak + Dkb)

a에서 b로 가는 최소 비용과 a에서 k를 거쳐 B로 가는 비용을 비교해서 더 작은 값으로 갱신하겠다는 의미이다.

1) 과정

다음과 같은 그래프가 있을 때, '연결된 간선'의 경우 값을 채워 넣고, 연결되지 않은 간선은 무한의 값을 넣는다.

여기서 무한은 우리가 보통 사용해왔던 int(1e9)를 사용하면 된다.

그리고 자기 자신으로 가는 비용은 0으로 적는다.

표로 살펴보면

출발/도착1번2번3번4번
1번04무한6
2번307무한
3번5무한04
4번무한무한20

- 단계 1

처음 1번 노드를 거쳐 가는 경우를 고려한다. 이때 점화식을 활용해서 모든 경우의 수를 넣으면 된다.

D23 = min(D23,D21+13)
D24 = min(D24,D21+14)
D32 = min(D32,D31+12)
D34 = min(D34,D31+14)
D42 = min(D42,D41+14)
D43 = min(D43,D41+13)

계산한 뒤 값을 갱신해주면 된다.

출발/도착1번2번3번4번
1번04무한6
2번3079
3번5904
4번무한무한20

- 단계 2

마찬 가지로 2번 노드를 거쳐 가는 경우를 계산한다.

출발/도착1번2번3번4번
1번04116
2번3079
3번5904
4번무한무한20

그 뒤 쭉쭉쭉쭉 남은 노드들을 계산해주면 다음과 같다.

출발/도착1번2번3번4번
1번0486
2번3079
3번5904
4번71120

2) 구현

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())

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("INF", end=" ")
        else:
            print(graph[a][b], end=" ")
print()
profile
잘하고싶다
post-custom-banner

0개의 댓글