|
| 1 | +package algo |
| 2 | + |
| 3 | +// BellmanFordSP ... |
| 4 | +type BellmanFordSP struct { |
| 5 | + distTo []float32 |
| 6 | + edgeTo []*DirectedEdge |
| 7 | + onQ []bool |
| 8 | + queue *Queue |
| 9 | + cost int |
| 10 | + cycle []*DirectedEdge |
| 11 | +} |
| 12 | + |
| 13 | +// NewBellmanFordSP ... |
| 14 | +func NewBellmanFordSP(g *EdgeWeightedDigraph, s int) *BellmanFordSP { |
| 15 | + edgeTo := make([]*DirectedEdge, g.V()) |
| 16 | + distTo := make([]float32, g.V()) |
| 17 | + onQ := make([]bool, g.V()) |
| 18 | + queue := NewQueue() |
| 19 | + for v := 0; v < g.V(); v++ { |
| 20 | + distTo[v] = PositiveInfinity |
| 21 | + } |
| 22 | + distTo[s] = 0.0 |
| 23 | + queue.Enqueue(s) |
| 24 | + onQ[s] = true |
| 25 | + b := &BellmanFordSP{distTo, edgeTo, onQ, queue, 0, nil} |
| 26 | + for !queue.IsEmpty() && !b.hasNegativeCycle() { |
| 27 | + v := queue.Dequeue().(int) |
| 28 | + b.onQ[v] = false |
| 29 | + b.relax(g, v) |
| 30 | + } |
| 31 | + return b |
| 32 | +} |
| 33 | + |
| 34 | +func (b *BellmanFordSP) relax(g *EdgeWeightedDigraph, v int) { |
| 35 | + for _, e := range g.Adj(v) { |
| 36 | + w := e.To() |
| 37 | + if b.distTo[w] > b.distTo[v]+e.Weight() { |
| 38 | + b.distTo[w] = b.distTo[v] + e.Weight() |
| 39 | + b.edgeTo[w] = e |
| 40 | + if !b.onQ[w] { |
| 41 | + b.queue.Enqueue(w) |
| 42 | + b.onQ[w] = true |
| 43 | + } |
| 44 | + } |
| 45 | + b.cost++ |
| 46 | + if b.cost%g.V() == 0 { |
| 47 | + b.findNegativeCycle() |
| 48 | + if b.hasNegativeCycle() { |
| 49 | + return // found a negative cycle |
| 50 | + } |
| 51 | + } |
| 52 | + } |
| 53 | +} |
| 54 | + |
| 55 | +func (b *BellmanFordSP) findNegativeCycle() { |
| 56 | + V := len(b.edgeTo) |
| 57 | + spt := NewEdgeWeightedDigraphV(V) |
| 58 | + for v := 0; v < V; v++ { |
| 59 | + if b.edgeTo[v] != nil { |
| 60 | + spt.AddEdge(b.edgeTo[v]) |
| 61 | + } |
| 62 | + } |
| 63 | + |
| 64 | + finder := NewEdgeWeightedDirectedCycle(spt) |
| 65 | + b.cycle = finder.Cycle() |
| 66 | +} |
| 67 | +func (b *BellmanFordSP) hasNegativeCycle() bool { |
| 68 | + return b.cycle != nil |
| 69 | +} |
| 70 | + |
| 71 | +// DistTo ... |
| 72 | +func (b *BellmanFordSP) DistTo(v int) float32 { |
| 73 | + return b.distTo[v] |
| 74 | +} |
| 75 | + |
| 76 | +// HasPathTo ... |
| 77 | +func (b *BellmanFordSP) HasPathTo(v int) bool { |
| 78 | + return b.distTo[v] < PositiveInfinity |
| 79 | +} |
| 80 | + |
| 81 | +// PathTo ... |
| 82 | +func (b *BellmanFordSP) PathTo(v int) (edges []*DirectedEdge) { |
| 83 | + if !b.HasPathTo(v) { |
| 84 | + return nil |
| 85 | + } |
| 86 | + |
| 87 | + for e := b.edgeTo[v]; e != nil; e = b.edgeTo[e.From()] { |
| 88 | + // stack |
| 89 | + edges = append([]*DirectedEdge{e}, edges...) |
| 90 | + } |
| 91 | + return |
| 92 | +} |
0 commit comments