-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbellman_ford.go
More file actions
83 lines (74 loc) · 1.63 KB
/
bellman_ford.go
File metadata and controls
83 lines (74 loc) · 1.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package grafo
// BellmanFord calculate the shortest path from v to all other vertices.
// The function returns the a slice of parent, a slice of dist containing the dists
// between v and the vertex and return ok if there isn't a negative cycle.
//
// The algorithm skip NaN weighted edges.
func BellmanFord[T IntegerOrFloat](g Graph[T], v int) (parent []int, dist []T, ok bool) {
// Adapted from https://www.ime.usp.br/~pf/algoritmos_para_grafos/aulas/bellman-ford.html.
n := g.Order()
inf := InfFor[T]()
parent = make([]int, n)
dist = make([]T, n)
onQueue := make([]bool, n)
for i := range n {
parent[i] = -1
dist[i] = inf
onQueue[i] = false
}
parent[v] = -1
dist[v] = 0
Q := newQueue(n)
Q.Push(v)
onQueue[v] = true
sentinel := n
Q.Push(sentinel)
k := 0
for {
v = Q.Pop()
if v < sentinel {
for w, weight := range g.EdgesFrom(v) {
if isNaN(weight) {
continue
}
alt := add(dist[v], weight)
if alt < dist[w] {
dist[w] = alt
parent[w] = v
if !onQueue[w] {
Q.Push(w)
onQueue[w] = true
}
}
}
} else {
if Q.Len() == 0 {
ok = true
break
}
k++
if k >= n {
ok = false // Negative cycle.
break
}
Q.Push(sentinel)
for i := range n {
onQueue[i] = false
}
}
}
return parent, dist, ok
}
// add add two numbers and check for overflow and
// underflow, if overflow occurs add return positive
// inf, if underflows it returns negative inf.
func add[T IntegerOrFloat](a, b T) T {
c := a + b
if a > 0 && b > 0 && c < a {
return InfFor[T]()
}
if a < 0 && b < 0 && c > a {
return InfFor[T]() + 1 // Negative inf.
}
return c
}