Given a weighted and directed graph of V vertices and E edges. An edge is represented as [ai, bi, wi], meaning there is a directed edge from ai to bi having weight wi. Find the shortest distance of all the vertices from the source vertex S. If a vertex can't be reached from the S then mark the distance as 109.
If the graph contains a negative cycle then return -1.
Input : V = 6, Edges = [[3, 2, 6], [5, 3, 1], [0, 1, 5], [1, 5, -3], [1, 2, -2], [3, 4, -2], [2, 4, 3]], S = 0
Output: 0 5 3 3 1 2
Explanation:
For node 1, shortest path is 0->1 (distance=5).
For node 2, shortest path is 0->1->2 (distance=3)
For node 3, shortest path is 0->1->5->3 (distance=3)
For node 4, shortest path is 0->1->5->3->4 (distance=1)
For node 5, shortest path is 0->1->5 (distance=2)
Input : V = 2, Edges = [[0,1,9]], S = 0
Output: 0 9
Explanation: For node 1, the shortest path is 0->1 (distance=9)
Input: V=3, Edges = [[0,1,5],[1,0,3],[1,2,-1],[2,0,1]], S = 2
The first thing that comes to mind when the requirement is to find shortest distance of all vertices from the source vertex S is Dijkstra's Algorithm. But this problem suggests that graphs can contain negative edges for which the Dijkstra's algorithm will fail.
To solve such issue, the Bellman Ford Algorithm will come in picture. It not only works when the graph contains negative edges, but also helps identify if the graph contains negative cycle (a cycle where sum of all weights is negative). The algorithm finds the minimum distance to reach any node by performing N-1 times Edge Relaxation (where N is the number of nodes in the graph). Though Bellman Ford Algorithm is more versatile, it is slower when compared to Dijkstra's Algorithm.
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
/* Function to implement
Bellman Ford Algorithm */
vector<int> bellman_ford(int V, vector<vector<int>>& edges,
int S) {
// To store the distance
vector<int> dist(V, 1e9);
// Distane of source from itself is zero
dist[S] = 0;
// Repeat for V-1 times
for(int i=0; i<V-1; i++) {
// Iterate on all the edges
for(auto it : edges) {
int u = it[0]; // node 1
int v = it[1]; // node 2
int wt = it[2]; // edge weight
// Edge relaxation
if(dist[u] != 1e9 &&
dist[u] + wt < dist[v]) {
// Updating the known distance
dist[v] = dist[u] + wt;
}
}
}
/* An extra relaxation to check if the
graph consists of a negative cycle */
for(auto it : edges) {
int u = it[0]; // node 1
int v = it[1]; // node 2
int wt = it[2]; // edge weight
/* If edge relaxation is possible,
negative cycle exists */
if(dist[u] != 1e9 &&
dist[u] + wt < dist[v]) {
// Return {-1}
return {-1};
}
}
// Return the computed result
return dist;
}
};
int main() {
int V = 6, S = 0;
vector<vector<int>> edges = {
{3, 2, 6}, {5, 3, 1},
{0, 1, 5}, {1, 5, -3},
{1, 2, -2}, {3, 4, -2},
{2, 4, 3}
};
/* Creating an instance of
Solution class */
Solution sol;
/* Function call to implement
Bellman Ford Algorithm */
vector<int> ans = sol.bellman_ford(V, edges, S);
// Output
if(ans == vector<int>(1, -1))
cout << "The graph contains negative cycle.";
else{
cout << "The shortest distance from source is: ";
for(int i=0; i < V; i++) {
cout << ans[i] << " ";
}
}
return 0;
}
import java.util.*;
class Solution {
/* Function to implement
Bellman Ford Algorithm */
public int[] bellman_ford(int V,
ArrayList<ArrayList<Integer>> edges,
int S) {
// To store the distance
int[] dist = new int[V];
Arrays.fill(dist, (int) 1e9);
// Distance of source from itself is zero
dist[S] = 0;
// Repeat for V-1 times
for(int i = 0; i < V-1; i++) {
// Iterate on all the edges
for(ArrayList<Integer> it : edges) {
int u = it.get(0); // node 1
int v = it.get(1); // node 2
int wt = it.get(2); // edge weight
// Edge relaxation
if(dist[u] != 1e9 &&
dist[u] + wt < dist[v]) {
// Updating the known distance
dist[v] = dist[u] + wt;
}
}
}
/* An extra relaxation to check if the
graph consists of a negative cycle */
for(ArrayList<Integer> it : edges) {
int u = it.get(0); // node 1
int v = it.get(1); // node 2
int wt = it.get(2); // edge weight
/* If edge relaxation is possible,
negative cycle exists */
if(dist[u] != 1e9 &&
dist[u] + wt < dist[v]) {
// Return {-1}
return new int[]{-1};
}
}
// Return the computed result
return dist;
}
public static void main(String[] args) {
int V = 6, S = 0;
ArrayList<ArrayList<Integer>> edges = new ArrayList<>();
edges.add(new ArrayList<>(Arrays.asList(3, 2, 6)));
edges.add(new ArrayList<>(Arrays.asList(5, 3, 1)));
edges.add(new ArrayList<>(Arrays.asList(0, 1, 5)));
edges.add(new ArrayList<>(Arrays.asList(1, 5, -3)));
edges.add(new ArrayList<>(Arrays.asList(1, 2, -2)));
edges.add(new ArrayList<>(Arrays.asList(3, 4, -2)));
edges.add(new ArrayList<>(Arrays.asList(2, 4, 3)));
/* Creating an instance of
Solution class */
Solution sol = new Solution();
/* Function call to implement
Bellman Ford Algorithm */
int[] ans = sol.bellman_ford(V, edges, S);
// Output
if(ans.length == 1 && ans[0] == -1)
System.out.println("The graph contains negative cycle.");
else{
System.out.print("The shortest distance from source is: ");
for(int i = 0; i < V; i++) {
System.out.print(ans[i] + " ");
}
}
}
}
class Solution:
# Function to implement
# Bellman Ford Algorithm
def bellman_ford(self, V, edges, S):
# To store the distance
dist = [int(1e9)] * V
# Distance of source from itself is zero
dist[S] = 0
# Repeat for V-1 times
for _ in range(V-1):
# Iterate on all the edges
for u, v, wt in edges:
# Edge relaxation
if (dist[u] != int(1e9) and
dist[u] + wt < dist[v]):
# Updating the known distance
dist[v] = dist[u] + wt
# An extra relaxation to check if the
# graph consists of a negative cycle
for u, v, wt in edges:
# If edge relaxation is possible,
# negative cycle exists
if (dist[u] != int(1e9) and
dist[u] + wt < dist[v]):
# Return [-1]
return [-1]
# Return the computed result
return dist
if __name__ == "__main__":
V, S = 6, 0
edges = [
[3, 2, 6], [5, 3, 1],
[0, 1, 5], [1, 5, -3],
[1, 2, -2], [3, 4, -2],
[2, 4, 3]
]
# Creating an instance of
# Solution class
sol = Solution()
# Function call to implement
# Bellman Ford Algorithm
ans = sol.bellman_ford(V, edges, S)
# Output
if ans == [-1]:
print("The graph contains negative cycle.")
else:
print("The shortest distance from source is: ", end=" ")
for d in ans:
print(d, end=" ")
class Solution {
/* Function to implement
Bellman Ford Algorithm */
bellman_ford(V, edges, S) {
// To store the distance
let dist = new Array(V).fill(1e9);
// Distance of source from itself is zero
dist[S] = 0;
// Repeat for V-1 times
for (let i = 0; i < V-1; i++) {
// Iterate on all the edges
for (let it of edges) {
let u = it[0]; // node 1
let v = it[1]; // node 2
let wt = it[2]; // edge weight
// Edge relaxation
if (dist[u] != 1e9 && dist[u] + wt < dist[v]) {
// Updating the known distance
dist[v] = dist[u] + wt;
}
}
}
/* An extra relaxation to check if the
graph consists of a negative cycle */
for (let it of edges) {
let u = it[0]; // node 1
let v = it[1]; // node 2
let wt = it[2]; // edge weight
/* If edge relaxation is possible,
negative cycle exists */
if (dist[u] != 1e9 && dist[u] + wt < dist[v]) {
// Return [-1]
return [-1];
}
}
// Return the computed result
return dist;
}
}
// Main function
let V = 6, S = 0;
let edges = [
[3, 2, 6], [5, 3, 1],
[0, 1, 5], [1, 5, -3],
[1, 2, -2], [3, 4, -2],
[2, 4, 3]
];
/* Creating an instance of
Solution class */
let sol = new Solution();
/* Function call to implement
Bellman Ford Algorithm */
let ans = sol.bellman_ford(V, edges, S);
// Output
if (ans.length === 1 && ans[0] === -1)
console.log("The graph contains negative cycle.");
else {
console.log("The shortest distance from source is: ", ans.join(" "));
}
Time Complexity: O(V*E)
All the E edges are relaxed for a total of V-1 times. And an extra iteration is performed to detect negative cycle, making the algorithm take O(V*E) time.
Space Complexity: O(V)
The distance array takes O(V) time.
Q: Why use Bellman-Ford instead of Dijkstra’s Algorithm?
A: Dijkstra’s Algorithm does not work with negative weights, whereas Bellman-Ford handles negative weights and detects cycles.
Q: Can we optimize Bellman-Ford?
A: Yes, using early stopping: If no distance updates occur in an iteration, we can terminate early.
Q: Can we improve performance further?
A: Using the SPFA Algorithm (Shortest Path Faster Algorithm), which is an optimized queue-based Bellman-Ford, improving efficiency for sparse graphs.
Q: How would you modify the algorithm to return the actual shortest path, not just distances?
A: Maintain a parent array to track the previous node in the shortest path and reconstruct it via backtracking.