2020. 8. 30. 03:22ㆍAlgorithm
Bellman-Ford Algorithm 번역+공부 (예제 코드는 kotlin)
* 문제: 주어진 그래프에서 시작 점(vertex)으로부터 모든 점까지의 최단 거리 찾기
- 그래프는 음수 가중치(negative weight)를 갖는 선(edge)을 가질 수 있다.
- 시간 복잡도: O(VE), V=점 갯수, E=선 갯수
- 음수 가중치를 갖는 선이 없다는 가정하에 이 문제를 해결하는 다른 알고리즘으로 Dijkstra가 있지만 별도로 다룬다.
* 입력: 그래프(directed graph), 시작점 src
* 출력: src로부터 모든 점까지의 최단 거리
- 음수 가중치가 순환되는 경우(negative weight cycle) 최단 거리를 계산할 수 없기 때문에 이에 대한 출력이 있어야 한다.
* step by step
(1) 시작점으로부터 모든 점들까지의 거리 초기화
- distance(시작점 -> 시작점) = 0
(2) 주어진 그래프에서 아래와 같은 과정을 |V|-1번 반복해 최단 거리 계산
- 시작점에서 어떤 점까지의 최단 경로에서 선(edge)은 최대 |V|-1개 나올 수 있기 때문에 |V|-1번 반복.
val dist = IntArray(V)
// src = 0, dist[0] = 0, dist[...rest] = Int.MAX_VALUE
for (i in 1 until V) {
for (edge in graph.edges) {
val u = edge.src
val v = edge.dest
if (dist[u] != Int.MAX_VALUE
&& dist[v] > dist[u] + edge.weight) {
dist[v] = dist[u] + edge.weight
}
} // inner
} // outer
(3) 음수 가중치가 순환되는 경우(negative weight cycle) 검사
- 순환이 없다는 가정 하에 (2) 과정에서 이미 시작점으로부터 모든 점들까지의 최단 거리 계산을 마쳤다.
- 그럼에도 불구하고 모든 선들에 대해서 다시 한번 최단 거리 갱신 과정을 수행했을 때((2) 과정의 inner 루프), 최단 거리가 갱신이 된다면 그래프가 순환됨을 알 수 있다.
for (edge in graph.edges) {
val u = edge.src
val v = edge.dest
if (dist[u] != Int.MAX_VALUE
&& dist[v] > dist[u] + edge.weight) {
println("found negative weight cycle in the graph")
return
}
}
* 동작 방식
이 알고리즘은 bottom-up 방식으로, (2) 과정에서 outer 루프의 i 번째 반복을 거치면 최대 i 개의 선을 가진 최단 거리가 계산된다.(proof)
다음은 이해를 돕기 위한 예제이다.
edge 순서가 (B,E), (D,B), (B,D), (A,B), (A,C), (D,C), (B,C), (E,D) 라고 가정하고
1번째 outer 루프가 실행되면 아래와 같이 최단 거리가 갱신된다.
- (B,E), (D,B), (B,D) 갱신없음
- (A,B) 1번째 갱신
- (A,C) 2번째 갱신
- (D,C) 갱신없음
- (B,C) 3번째 갱신 - 앞서 B까지의 최단 거리가 갱신되었기 때문에 가능
- (E,D) 갱신없음
위 과정대로라면 (B,E) -> (B,D) -> (E,D) 순서로 최단 거리가 갱신된다.
이 예제에서는 |V|=5 라서 outer loop가 4번 수행되지만,
이미 최대 2개의 선(edge)를 갖는, 시작점 A부터 다른 점들까지의 최단 거리 계산이 완료된다.
* 직접 실행해본, 테스트 샘플 코드
- kotlin playground 에서 바로 실행해볼 수 있다.
- 테스트 그래프 2개 중 1개는 위 예제 그래프를 사용했지만 outer loop 1번째에서 모든 계산이 완료된 이유는 등록한 edge 순서가 다르기 때문임을 감안
gist.github.com/Kelicia91/5233e9ee95357785c59f4a146f32a5a0
bellman-ford-algorithm
bellman-ford-algorithm. GitHub Gist: instantly share code, notes, and snippets.
gist.github.com
출처: https://www.geeksforgeeks.org/bellman-ford-algorithm-dp-23/