Given a weighted graph with V vertices and E edges, along with a source vertex src
, the task is to compute the shortest distances from the source to all other vertices. If a vertex is unreachable from the source, its distance should be marked as 108. In the presence of a negative weight cycle, return -1 to signify that shortest path calculations are not feasible.
Examples:
Input: V = 5, edges = [[0, 1, 5], [1, 2, 1], [1, 3, 2], [2, 4, 1], [4, 3, -1]], src = 0
Output: [0, 5, 6, 6, 7]
Explanation: Shortest Paths:
For 0 to 1 minimum distance will be 5. By following path 0 → 1
For 0 to 2 minimum distance will be 6. By following path 0 → 1 → 2
For 0 to 3 minimum distance will be 6. By following path 0 → 1 → 2 → 4 → 3
For 0 to 4 minimum distance will be 7. By following path 0 → 1 → 2 → 4
Input: V = 4, edges = [[0, 1, 4], [1, 2, -6], [2, 3, 5], [3, 1, -2]], src = 0
Output: [-1]
Explanation: The graph contains a negative weight cycle formed by the path 1 → 2 → 3 → 1, where the total weight of the cycle is negative.
Approach: Bellman-Ford Algorithm - O(V*E) Time and O(V) Space
Negative weight cycle:
A negative weight cycle is a cycle in a graph, whose sum of edge weights is negative. If you traverse the cycle, the total weight accumulated would be less than zero.
In the presence of negative weight cycle in the graph, the shortest path doesn't exist because with each traversal of the cycle shortest path keeps decreasing.
Limitation of Dijkstra's Algorithm:
Since, we need to find the single source shortest path, we might initially think of using Dijkstra's algorithm. However, Dijkstra is not suitable when the graph consists of negative edges. The reason is, it doesn't revisit those nodes which have already been marked as visited. If a shorter path exists through a longer route with negative edges, Dijkstra's algorithm will fail to handle it.
Principle of Relaxation of Edges
- Relaxation means updating the shortest distance to a node if a shorter path is found through another node. For an edge (u, v) with weight w:
- If going through u gives a shorter path to v from the source node (i.e., distance[v] > distance[u] + w), we update the distance[v] as distance[u] + w.
- In the bellman-ford algorithm, this process is repeated (V - 1) times for all the edges.
Why Relaxing Edges (V - 1) times gives us Single Source Shortest Path?
A shortest path between two vertices can have at most (V - 1) edges. It is not possible to have a simple path with more than (V - 1) edges (otherwise it would form a cycle). Therefore, repeating the relaxation process (V - 1) times ensures that all possible paths between source and any other node have been covered.
Assuming node 0 as the source vertex, let's see how we can relax the edges to find the shortest paths:
- In the first relaxation, since the shortest paths for vertices 1 and 2 are unknown (infinite, i.e., 108), the shortest paths for vertices 2 and 3 will also remain infinite (108)
. And, for vertex 1, the distance will be updated to 4, as dist[0] + 4 < dist[1]
(i.e., 0 + 4 <
108). - In the second relaxation, the shortest path for vertex 2 is still infinite (e.g. 108), which means the shortest path for vertex 3 will also remain infinite. For vertex 2, the distance can be updated to 3, as dist[1] + (-1) = 3.
- In the third relaxation, the shortest path for vertex 3 will be updated to 5, as dist[2] + 2 = 5.
So, in above example, dist[1] is updated in 1st relaxation, dist[2] is updated in second relaxation, so the dist for the last node (V - 1), will be updated in (V - 1) th relaxation.
Detection of a Negative Weight Cycle
- As we have discussed earlier that, we need (V - 1) relaxations of all the edges to achieve single source shortest path. If one additional relaxation (Vth) for any edge is possible, it indicates that some edges with overall negative weight has been traversed once more. This indicates the presence of a negative weight cycle in the graph.
Bellman-Ford is a single source shortest path algorithm. It effectively works in the cases of negative edges and is able to detect negative cycles as well. It works on the principle of relaxation of the edges.
Illustration:
C++
#include <iostream>
#include <vector>
using namespace std;
vector<int> bellmanFord(int V, vector<vector<int>>& edges, int src) {
// Initially distance from source to all
// other vertices is not known(Infinite).
vector<int> dist(V, 1e8);
dist[src] = 0;
// Relaxation of all the edges V times, not (V - 1) as we
// need one additional relaxation to detect negative cycle
for (int i = 0; i < V; i++) {
for (vector<int> edge : edges) {
int u = edge[0];
int v = edge[1];
int wt = edge[2];
if (dist[u] != 1e8 && dist[u] + wt < dist[v]) {
// If this is the Vth relaxation, then there is
// a negative cycle
if(i == V - 1)
return {-1};
// Update shortest distance to node v
dist[v] = dist[u] + wt;
}
}
}
return dist;
}
int main() {
// Number of vertices in the graph
int V = 5;
// Edge list representation: {source, destination, weight}
vector<vector<int>> edges = {
{1, 3, 2},
{4, 3, -1},
{2, 4, 1},
{1, 2, 1},
{0, 1, 5}
};
// Define the source vertex
int src = 0;
// Run Bellman-Ford algorithm to get shortest paths from src
vector<int> ans = bellmanFord(V, edges, src);
// Output the shortest distances from src to all vertices
for (int dist : ans)
cout << dist << " ";
return 0;
}
Java
import java.util.Arrays;
class GfG {
static int[] bellmanFord(int V, int[][] edges, int src) {
// Initially distance from source to all other vertices
// is not known(Infinite).
int[] dist = new int[V];
Arrays.fill(dist, (int)1e8);
dist[src] = 0;
// Relaxation of all the edges V times, not (V - 1) as we
// need one additional relaxation to detect negative cycle
for (int i = 0; i < V; i++) {
for (int[] edge : edges) {
int u = edge[0];
int v = edge[1];
int wt = edge[2];
if (dist[u] != 1e8 && dist[u] + wt < dist[v]) {
// If this is the Vth relaxation, then there is
// a negative cycle
if (i == V - 1)
return new int[]{-1};
// Update shortest distance to node v
dist[v] = dist[u] + wt;
}
}
}
return dist;
}
public static void main(String[] args) {
// Number of vertices in the graph
int V = 5;
// Edge list representation: {source, destination, weight}
int[][] edges = new int[][] {
{1, 3, 2},
{4, 3, -1},
{2, 4, 1},
{1, 2, 1},
{0, 1, 5}
};
// Source vertex for Bellman-Ford algorithm
int src = 0;
// Run Bellman-Ford algorithm from the source vertex
int[] ans = bellmanFord(V, edges, src);
// Print shortest distances from the source to all vertices
for (int dist : ans)
System.out.print(dist + " ");
}
}
Python
def bellmanFord(V, edges, src):
# Initially distance from source to all other vertices
# is not known(Infinite) e.g. 1e8.
dist = [100000000] * V
dist[src] = 0
# Relaxation of all the edges V times, not (V - 1) as we
# need one additional relaxation to detect negative cycle
for i in range(V):
for edge in edges:
u, v, wt = edge
if dist[u] != 100000000 and dist[u] + wt < dist[v]:
# If this is the Vth relaxation, then there
# is a negative cycle
if i == V - 1:
return [-1]
# Update shortest distance to node v
dist[v] = dist[u] + wt
return dist
if __name__ == '__main__':
V = 5
edges = [[1, 3, 2], [4, 3, -1], [2, 4, 1], [1, 2, 1], [0, 1, 5]]
src = 0
ans = bellmanFord(V, edges, src)
print(' '.join(map(str, ans)))
C#
using System;
class GfG {
// Function to perform the Bellman-Ford algorithm
static int[] bellmanFord(int V, int[,] edges, int src) {
// Initialize distances from source to all
// vertices as "infinity" (represented by 1e8)
int[] dist = new int[V];
for (int i = 0; i < V; i++)
dist[i] = (int)1e8;
// Distance to the source is always 0
dist[src] = 0;
// Get the number of edges from the 2D edge array
int E = edges.GetLength(0);
// Relax all edges V times
// The extra iteration (V-th) is used to detect a
// negative weight cycle
for (int i = 0; i < V; i++) {
for (int j = 0; j < E; j++) {
// Extract edge info: from u to v with weight wt
int u = edges[j, 0];
int v = edges[j, 1];
int wt = edges[j, 2];
// Only proceed if u has already been reached
// (i.e., not infinity)
if (dist[u] != (int)1e8 && dist[u] + wt < dist[v]) {
// If this is the V-th iteration and relaxation is still
// possible, it means there is a negative weight cycle
if (i == V - 1)
// Indicate presence of negative cycle
return new int[] { -1 };
// Update the distance to vertex v through vertex u
dist[v] = dist[u] + wt;
}
}
}
// Return the final shortest distances
return dist;
}
static void Main() {
// Number of vertices in the graph
int V = 5;
// Edge list: each row represents {source, destination, weight}
int[,] edges = {
{ 1, 3, 2 },
{ 4, 3, -1 },
{ 2, 4, 1 },
{ 1, 2, 1 },
{ 0, 1, 5 }
};
// Source vertex
int src = 0;
// Call Bellman-Ford and store the result
int[] ans = bellmanFord(V, edges, src);
// Print the shortest distances from source to all vertices
foreach (int d in ans)
Console.Write(d + " ");
}
}
JavaScript
function bellmanFord(V, edges, src) {
// Initially distance from source to all
// other vertices is not known(Infinite).
let dist = new Array(V).fill(1e8);
dist[src] = 0;
// Relaxation of all the edges V times, not (V - 1) as we
// need one additional relaxation to detect negative cycle
for (let i = 0; i < V; i++) {
for (let edge of edges) {
let u = edge[0];
let v = edge[1];
let wt = edge[2];
if (dist[u] !== 1e8 && dist[u] + wt < dist[v]) {
// If this is the Vth relaxation, then there is
// a negative cycle
if (i === V - 1)
return [-1];
// Update shortest distance to node v
dist[v] = dist[u] + wt;
}
}
}
return dist;
}
// Driver Code
let V = 5;
let edges = [
[1, 3, 2],
[4, 3, -1],
[2, 4, 1],
[1, 2, 1],
[0, 1, 5]
];
let src = 0;
let ans = bellmanFord(V, edges, src);
console.log(ans.join(" "));
Problems based on Shortest Path
Similar Reads
Basics & Prerequisites
Data Structures
Array Data StructureIn this article, we introduce array, implementation in different popular languages, its basic operations and commonly seen problems / interview questions. An array stores items (in case of C/C++ and Java Primitive Arrays) or their references (in case of Python, JS, Java Non-Primitive) at contiguous
3 min read
String in Data StructureA string is a sequence of characters. The following facts make string an interesting data structure.Small set of elements. Unlike normal array, strings typically have smaller set of items. For example, lowercase English alphabet has only 26 characters. ASCII has only 256 characters.Strings are immut
2 min read
Hashing in Data StructureHashing is a technique used in data structures that efficiently stores and retrieves data in a way that allows for quick access. Hashing involves mapping data to a specific index in a hash table (an array of items) using a hash function. It enables fast retrieval of information based on its key. The
2 min read
Linked List Data StructureA linked list is a fundamental data structure in computer science. It mainly allows efficient insertion and deletion operations compared to arrays. Like arrays, it is also used to implement other data structures like stack, queue and deque. Hereâs the comparison of Linked List vs Arrays Linked List:
2 min read
Stack Data StructureA Stack is a linear data structure that follows a particular order in which the operations are performed. The order may be LIFO(Last In First Out) or FILO(First In Last Out). LIFO implies that the element that is inserted last, comes out first and FILO implies that the element that is inserted first
2 min read
Queue Data StructureA Queue Data Structure is a fundamental concept in computer science used for storing and managing data in a specific order. It follows the principle of "First in, First out" (FIFO), where the first element added to the queue is the first one to be removed. It is used as a buffer in computer systems
2 min read
Tree Data StructureTree Data Structure is a non-linear data structure in which a collection of elements known as nodes are connected to each other via edges such that there exists exactly one path between any two nodes. Types of TreeBinary Tree : Every node has at most two childrenTernary Tree : Every node has at most
4 min read
Graph Data StructureGraph Data Structure is a collection of nodes connected by edges. It's used to represent relationships between different entities. If you are looking for topic-wise list of problems on different topics like DFS, BFS, Topological Sort, Shortest Path, etc., please refer to Graph Algorithms. Basics of
3 min read
Trie Data StructureThe Trie data structure is a tree-like structure used for storing a dynamic set of strings. It allows for efficient retrieval and storage of keys, making it highly effective in handling large datasets. Trie supports operations such as insertion, search, deletion of keys, and prefix searches. In this
15+ min read
Algorithms
Searching AlgorithmsSearching algorithms are essential tools in computer science used to locate specific items within a collection of data. In this tutorial, we are mainly going to focus upon searching in an array. When we search an item in an array, there are two most common algorithms used based on the type of input
2 min read
Sorting AlgorithmsA Sorting Algorithm is used to rearrange a given array or list of elements in an order. For example, a given array [10, 20, 5, 2] becomes [2, 5, 10, 20] after sorting in increasing order and becomes [20, 10, 5, 2] after sorting in decreasing order. There exist different sorting algorithms for differ
3 min read
Introduction to RecursionThe process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function. A recursive algorithm takes one step toward solution and then recursively call itself to further move. The algorithm stops once we reach the solution
14 min read
Greedy AlgorithmsGreedy algorithms are a class of algorithms that make locally optimal choices at each step with the hope of finding a global optimum solution. At every step of the algorithm, we make a choice that looks the best at the moment. To make the choice, we sometimes sort the array so that we can always get
3 min read
Graph AlgorithmsGraph is a non-linear data structure like tree data structure. The limitation of tree is, it can only represent hierarchical data. For situations where nodes or vertices are randomly connected with each other other, we use Graph. Example situations where we use graph data structure are, a social net
3 min read
Dynamic Programming or DPDynamic Programming is an algorithmic technique with the following properties.It is mainly an optimization over plain recursion. Wherever we see a recursive solution that has repeated calls for the same inputs, we can optimize it using Dynamic Programming. The idea is to simply store the results of
3 min read
Bitwise AlgorithmsBitwise algorithms in Data Structures and Algorithms (DSA) involve manipulating individual bits of binary representations of numbers to perform operations efficiently. These algorithms utilize bitwise operators like AND, OR, XOR, NOT, Left Shift, and Right Shift.BasicsIntroduction to Bitwise Algorit
4 min read
Advanced
Segment TreeSegment Tree is a data structure that allows efficient querying and updating of intervals or segments of an array. It is particularly useful for problems involving range queries, such as finding the sum, minimum, maximum, or any other operation over a specific range of elements in an array. The tree
3 min read
Pattern SearchingPattern searching algorithms are essential tools in computer science and data processing. These algorithms are designed to efficiently find a particular pattern within a larger set of data. Patten SearchingImportant Pattern Searching Algorithms:Naive String Matching : A Simple Algorithm that works i
2 min read
GeometryGeometry is a branch of mathematics that studies the properties, measurements, and relationships of points, lines, angles, surfaces, and solids. From basic lines and angles to complex structures, it helps us understand the world around us.Geometry for Students and BeginnersThis section covers key br
2 min read
Interview Preparation
Practice Problem