Bellman Ford Algorithm Negative Weights in DSA C# - Time & Space Complexity
We want to understand how the Bellman Ford algorithm's running time changes as the graph size grows.
Specifically, how does it handle graphs with negative weights efficiently?
Analyze the time complexity of the following Bellman Ford code snippet.
// Bellman Ford to find shortest paths
// from source in graph with negative weights
for (int i = 1; i <= vertices - 1; i++) {
foreach (var edge in edges) {
int u = edge.Source;
int v = edge.Destination;
int w = edge.Weight;
if (dist[u] != int.MaxValue && dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
}
}
}
This code relaxes all edges multiple times to find shortest paths, even with negative weights.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Relaxing all edges in the graph.
- How many times: The outer loop runs (vertices - 1) times, and inside it, all edges are checked once each time.
Each vertex causes a full pass over all edges, so the work grows with both vertices and edges.
| Input Size (vertices, edges) | Approx. Operations |
|---|---|
| 10 vertices, 20 edges | ~ 9 * 20 = 180 edge relaxations |
| 100 vertices, 500 edges | ~ 99 * 500 = 49,500 edge relaxations |
| 1000 vertices, 2000 edges | ~ 999 * 2000 = 1,998,000 edge relaxations |
Pattern observation: The total work grows roughly by multiplying the number of vertices by the number of edges.
Time Complexity: O(V * E)
This means the time grows proportionally to the number of vertices times the number of edges in the graph.
[X] Wrong: "Bellman Ford runs as fast as Dijkstra's algorithm, so it should be O(E log V)."
[OK] Correct: Bellman Ford checks all edges multiple times to handle negative weights, so it takes longer than Dijkstra's algorithm which uses a priority queue.
Understanding Bellman Ford's time complexity helps you explain why it is chosen for graphs with negative weights despite being slower than other algorithms.
"What if we stopped the algorithm early when no distances change in an iteration? How would that affect the time complexity?"
Practice
Solution
Step 1: Understand Bellman-Ford's capability
The Bellman-Ford algorithm is designed to find shortest paths from a single source vertex to all other vertices in a graph, even if some edges have negative weights.Step 2: Compare with other algorithms
Unlike Dijkstra's algorithm, Bellman-Ford can handle negative weights and also detect negative weight cycles.Final Answer:
To find the shortest path from a single source to all vertices, even with negative weights -> Option AQuick Check:
Bellman-Ford finds shortest paths with negative weights [OK]
- Confusing Bellman-Ford with algorithms for minimum spanning trees
- Thinking it only detects cycles without finding paths
- Assuming it cannot handle negative weights
Solution
Step 1: Understand array initialization with default values
Using Enumerable.Repeat(int.MaxValue, n).ToArray() creates an array filled with int.MaxValue for all elements.Step 2: Set source distance to zero
After initialization, setting dist[0] = 0 correctly sets the source vertex distance.Final Answer:
int[] dist = Enumerable.Repeat(int.MaxValue, n).ToArray(); dist[0] = 0; -> Option DQuick Check:
Correct array initialization with source zero [OK]
- Using dist.Fill which is not a valid method in C# arrays
- Setting dist[0] before initializing the array
- Not initializing all elements to int.MaxValue
int n = 4;
int[] dist = {0, int.MaxValue, int.MaxValue, int.MaxValue};
(int u, int v, int w)[] edges = {
(0, 1, 1),
(1, 2, -1),
(2, 3, -1),
(3, 1, -1)
};
foreach(var edge in edges) {
if(dist[edge.u] != int.MaxValue && dist[edge.u] + edge.w < dist[edge.v]) {
dist[edge.v] = dist[edge.u] + edge.w;
}
}
Console.WriteLine(string.Join(", ", dist));Solution
Step 1: Relax edge (0,1,1)
dist[0] = 0, so dist[1] = min(int.MaxValue, 0+1) = 1Step 2: Relax edge (1,2,-1)
dist[1] = 1, so dist[2] = min(int.MaxValue, 1-1) = 0Step 3: Relax edge (2,3,-1)
dist[2] = 0, so dist[3] = min(int.MaxValue, 0-1) = -1Step 4: Relax edge (3,1,-1)
dist[3] = -1, so dist[1] = min(1, -1-1) = -2Final Answer:
0, -2, 0, -1 -> Option CQuick Check:
Distances updated correctly after one iteration [OK]
- Not updating dist[1] after last edge relaxation
- Ignoring negative weights in relaxation
- Assuming no change if dist[v] is int.MaxValue
bool HasNegativeCycle(int n, (int u, int v, int w)[] edges, int source) {
int[] dist = Enumerable.Repeat(int.MaxValue, n).ToArray();
dist[source] = 0;
for(int i = 1; i <= n; i++) {
foreach(var edge in edges) {
if(dist[edge.u] != int.MaxValue && dist[edge.u] + edge.w < dist[edge.v]) {
dist[edge.v] = dist[edge.u] + edge.w;
if(i == n) return true;
}
}
}
return false;
}Solution
Step 1: Understand Bellman-Ford iteration count
Bellman-Ford relaxes edges exactly n-1 times to find shortest paths without negative cycles.Step 2: Detect negative cycle on nth iteration
If any edge can still be relaxed on the nth iteration, a negative cycle exists.Step 3: Identify loop range error
The code runs the loop from 1 to n inclusive. Bellman-Ford should relax edges exactly n-1 times, then check separately on the nth iteration.Final Answer:
The loop should run from 1 to n-1, not 1 to n -> Option AQuick Check:
Relax edges n-1 times before checking cycle [OK]
- Running relaxation loop n times instead of n-1
- Initializing distances incorrectly
- Returning true inside inner loop prematurely
Solution
Step 1: Recall Bellman-Ford relaxation count rule
Bellman-Ford requires relaxing all edges exactly n-1 times, where n is the number of vertices.Step 2: Apply to given graph
For 5 vertices, the algorithm must relax edges 5-1 = 4 times to guarantee shortest paths.Final Answer:
4 times -> Option BQuick Check:
Relax edges n-1 times for n vertices [OK]
- Relaxing edges n times instead of n-1
- Confusing number of edges with number of vertices
- Assuming negative weights require more iterations
Ready to prove it?
Pass the test and this pattern moves unknown
