Bellman Ford Algorithm Negative Weights in DSA Go - Time & Space Complexity
We want to understand how the Bellman Ford algorithm's running time changes as the graph size grows.
Specifically, how does the number of edges and vertices affect the work done?
Analyze the time complexity of the following code snippet.
func BellmanFord(edges [][]int, V int, src int) []int {
dist := make([]int, V)
for i := range dist {
dist[i] = 1<<31 - 1 // infinity
}
dist[src] = 0
for i := 0; i < V-1; i++ {
for _, edge := range edges {
u, v, w := edge[0], edge[1], edge[2]
if dist[u] != 1<<31-1 && dist[u]+w < dist[v] {
dist[v] = dist[u] + w
}
}
}
return dist
}
This code finds shortest paths from a source to all vertices, even with negative weights, by relaxing edges repeatedly.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The inner loop that goes through all edges to update distances.
- How many times: This inner loop runs once for each vertex minus one, so (V-1) times.
Each vertex causes the algorithm to check all edges once, so the total work grows with both vertices and edges.
| Input Size (V, E) | Approx. Operations |
|---|---|
| V=10, E=20 | About 9 * 20 = 180 checks |
| V=100, E=200 | About 99 * 200 = 19,800 checks |
| V=1000, E=2000 | About 999 * 2000 = 1,998,000 checks |
Pattern observation: The work grows roughly by multiplying the number of vertices and edges.
Time Complexity: O(V * E)
This means the time needed grows proportionally to the number of vertices times the number of edges.
[X] Wrong: "The algorithm runs in O(E) time because it just loops over edges."
[OK] Correct: The edge loop runs multiple times--once for each vertex minus one--so total work depends on both vertices and edges.
Understanding this time complexity helps you explain why Bellman Ford is slower than other shortest path algorithms but necessary for graphs with negative weights.
"What if we stopped the algorithm early when no distances change in an iteration? How would the time complexity change?"
Practice
Bellman-Ford algorithm compared to Dijkstra's algorithm?Solution
Step 1: Understand Dijkstra's limitation
Dijkstra's algorithm cannot handle negative weight edges because it assumes once a node is visited with the shortest path, it won't be updated again.Step 2: Bellman-Ford's capability
Bellman-Ford algorithm relaxes edges multiple times and can detect negative weight edges, allowing it to work correctly even with negative weights.Final Answer:
It can handle graphs with negative weight edges. -> Option CQuick Check:
Negative weights handled = B [OK]
- Thinking Bellman-Ford is always faster
- Believing it uses less memory than Dijkstra
- Assuming it only works on acyclic graphs
Solution
Step 1: Understand distance initialization
Distances to all vertices except the source should be set to a very large number (infinity) to represent unknown distance.Step 2: Use math.MaxInt32 for infinity
In Go, math.MaxInt32 is used to represent a large integer value for initialization.Final Answer:
dist := make([]int, V); for i := range dist { dist[i] = math.MaxInt32 } -> Option AQuick Check:
Initialize distances to max int = A [OK]
- Initializing distances to zero
- Using negative values for distances
- Not initializing distances at all
edges = []Edge{{0,1,4}, {0,2,5}, {1,2,-3}, {2,3,4}} starting from source 0?Solution
Step 1: Initialize distances
dist = [0, ∞, ∞, ∞]Step 2: Relax edges repeatedly
After first relaxation: dist[1]=4, dist[2]=5
After second relaxation: dist[2]=min(5,4 + (-3))=1
After third relaxation: dist[3]=dist[2] + 4 = 1 + 4 = 5
After further relaxations no changes occur.Final Answer:
[0, 4, 1, 5] -> Option BQuick Check:
Relax edges stepwise = A [OK]
- Not updating dist[2] after negative edge relaxation
- Adding weights incorrectly
- Confusing edge directions
for i := 0; i < V; i++ {
for _, e := range edges {
if dist[e.src] + e.weight < dist[e.dest] {
dist[e.dest] = dist[e.src] + e.weight
}
}
}Solution
Step 1: Check loop iteration count
Bellman-Ford requires relaxing edges exactly V-1 times to find shortest paths correctly.Step 2: Identify off-by-one error
The loop runs V times, which is one extra iteration and may cause incorrect behavior or unnecessary work.Final Answer:
Loop should run V-1 times, not V times. -> Option AQuick Check:
Relax edges V-1 times = A [OK]
- Running loop V times instead of V-1
- Using wrong comparison operator
- Not initializing dist array
edges = []Edge{{0,1,1}, {1,2,-1}, {2,3,-1}, {3,1,-1}}and source vertex 0, what does Bellman-Ford detect after running?
Solution
Step 1: Analyze edges for cycles
The edges form a cycle 1 -> 2 -> 3 -> 1 with total weight -3 (negative cycle).Step 2: Bellman-Ford cycle detection
After V-1 relaxations, one more relaxation detects if any distance can still be reduced, indicating a negative cycle.Final Answer:
Negative weight cycle detected involving vertices 1, 2, 3. -> Option DQuick Check:
Negative cycle detection = D [OK]
- Ignoring negative cycles
- Assuming zero-weight edges cause failure
- Thinking no cycle exists
Ready to prove it?
Pass the test and this pattern moves unknown
