Given a weighted directed graph containing V vertices numbered from 0 to V - 1 and a list of E directed edges edges[][], determine whether the graph contains a negative weight cycle or not.
Each edge is represented as: [u, v, w], where there is a directed edge from vertex u to vertex v having the given weight w.
Note: A negative-weight cycle is a cycle in a graph whose edges sum to a negative value.
[Naive Approach] Using Floyd–Warshall - O(V ^ 3) Time and O(V ^ 2) Space
The idea is to use a distance matrix where dist[u][v] stores the minimum known distance from vertex u to vertex v.
Initially:
Set dist[i][i] = 0.
For every edge [u, v, w], set dist[u][v] to the minimum edge weight between u and v.
Set all other distances to infinity.
Then apply the Floyd–Warshall algorithm by considering every vertex as an intermediate vertex.
If at any point after computing all shortest paths, dist[i][i] < 0 for any vertex i, it means there exists a path from i back to itself with negative total weight. Hence, the graph contains a negative weight cycle.
C++
#include<iostream>#include<vector>#include<climits>usingnamespacestd;boolisNegativeWeightCycle(intV,vector<vector<int>>&edges){constlonglongINF=LLONG_MAX/4;vector<vector<longlong>>dist(V,vector<longlong>(V,INF));// Distance from every vertex to itself is 0.for(inti=0;i<V;i++){dist[i][i]=0;}// Add all directed edges.for(constauto&edge:edges){intu=edge[0];intv=edge[1];intw=edge[2];dist[u][v]=min(dist[u][v],(longlong)w);}// Apply Floyd-Warshall algorithm.for(intk=0;k<V;k++){for(inti=0;i<V;i++){if(dist[i][k]==INF){continue;}for(intj=0;j<V;j++){if(dist[k][j]==INF){continue;}dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);}}}// A negative diagonal value confirms a negative cycle.for(inti=0;i<V;i++){if(dist[i][i]<0){returntrue;}}returnfalse;}intmain(){intV1=4;vector<vector<int>>edges1={{0,3,6},{1,0,4},{1,2,6},{3,1,2}};cout<<(isNegativeWeightCycle(V1,edges1)?"true":"false")<<"\n";intV2=4;vector<vector<int>>edges2={{1,0,4},{3,1,-2},{1,2,-6},{2,3,5}};cout<<(isNegativeWeightCycle(V2,edges2)?"true":"false")<<"\n";return0;}
Java
importjava.util.*;classGFG{staticbooleanisNegativeWeightCycle(intV,int[][]edges){longINF=Long.MAX_VALUE/4;long[][]dist=newlong[V][V];for(inti=0;i<V;i++){Arrays.fill(dist[i],INF);dist[i][i]=0;}// Add all directed edges.for(int[]edge:edges){intu=edge[0];intv=edge[1];intw=edge[2];dist[u][v]=Math.min(dist[u][v],w);}// Apply Floyd-Warshall algorithm.for(intk=0;k<V;k++){for(inti=0;i<V;i++){if(dist[i][k]==INF){continue;}for(intj=0;j<V;j++){if(dist[k][j]==INF){continue;}dist[i][j]=Math.min(dist[i][j],dist[i][k]+dist[k][j]);}}}// A negative diagonal value confirms a negative cycle.for(inti=0;i<V;i++){if(dist[i][i]<0){returntrue;}}returnfalse;}publicstaticvoidmain(String[]args){intV1=4;int[][]edges1={{0,3,6},{1,0,4},{1,2,6},{3,1,2}};System.out.println(isNegativeWeightCycle(V1,edges1));intV2=4;int[][]edges2={{1,0,4},{3,1,-2},{1,2,-6},{2,3,5}};System.out.println(isNegativeWeightCycle(V2,edges2));}}
Python
defisNegativeWeightCycle(V:int,edges:list[list[int]])->bool:INF=float("inf")dist=[[INF]*Vfor_inrange(V)]# Distance from every vertex to itself is 0.foriinrange(V):dist[i][i]=0# Add all directed edges.foru,v,winedges:dist[u][v]=min(dist[u][v],w)# Apply Floyd-Warshall algorithm.forkinrange(V):foriinrange(V):ifdist[i][k]==INF:continueforjinrange(V):ifdist[k][j]==INF:continuedist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j])# A negative diagonal value confirms a negative cycle.foriinrange(V):ifdist[i][i]<0:returnTruereturnFalseif__name__=="__main__":V1=4edges1=[[0,3,6],[1,0,4],[1,2,6],[3,1,2]]print(str(isNegativeWeightCycle(V1,edges1)).lower())V2=4edges2=[[1,0,4],[3,1,-2],[1,2,-6],[2,3,5]]print(str(isNegativeWeightCycle(V2,edges2)).lower())
C#
usingSystem;classGFG{staticboolisNegativeWeightCycle(intV,int[,]edges){longINF=long.MaxValue/4;long[,]dist=newlong[V,V];for(inti=0;i<V;i++){for(intj=0;j<V;j++){dist[i,j]=INF;}dist[i,i]=0;}intE=edges.GetLength(0);// Add all directed edges.for(inti=0;i<E;i++){intu=edges[i,0];intv=edges[i,1];intw=edges[i,2];dist[u,v]=Math.Min(dist[u,v],w);}// Apply Floyd-Warshall algorithm.for(intk=0;k<V;k++){for(inti=0;i<V;i++){if(dist[i,k]==INF){continue;}for(intj=0;j<V;j++){if(dist[k,j]==INF){continue;}dist[i,j]=Math.Min(dist[i,j],dist[i,k]+dist[k,j]);}}}// A negative diagonal value confirms a negative cycle.for(inti=0;i<V;i++){if(dist[i,i]<0){returntrue;}}returnfalse;}staticvoidMain(){intV1=4;int[,]edges1={{0,3,6},{1,0,4},{1,2,6},{3,1,2}};Console.WriteLine(isNegativeWeightCycle(V1,edges1).ToString().ToLower());intV2=4;int[,]edges2={{1,0,4},{3,1,-2},{1,2,-6},{2,3,5}};Console.WriteLine(isNegativeWeightCycle(V2,edges2).ToString().ToLower());}}
JavaScript
functionisNegativeWeightCycle(V,edges){constINF=Number.POSITIVE_INFINITY;constdist=Array.from({length:V},()=>newArray(V).fill(INF));// Distance from every vertex to itself is 0.for(leti=0;i<V;i++){dist[i][i]=0;}// Add all directed edges.for(const[u,v,w]ofedges){dist[u][v]=Math.min(dist[u][v],w);}// Apply Floyd-Warshall algorithm.for(letk=0;k<V;k++){for(leti=0;i<V;i++){if(dist[i][k]===INF){continue;}for(letj=0;j<V;j++){if(dist[k][j]===INF){continue;}dist[i][j]=Math.min(dist[i][j],dist[i][k]+dist[k][j]);}}}// A negative diagonal value confirms a negative cycle.for(leti=0;i<V;i++){if(dist[i][i]<0){returntrue;}}returnfalse;}// Driver CodeconstV1=4;constedges1=[[0,3,6],[1,0,4],[1,2,6],[3,1,2]];console.log(isNegativeWeightCycle(V1,edges1));constV2=4;constedges2=[[1,0,4],[3,1,-2],[1,2,-6],[2,3,5]];console.log(isNegativeWeightCycle(V2,edges2));
Output
false
true
[Expected Approach] Using Bellman–Ford - O(V * E) and O(V) Space
The idea is to initialize the distance of every vertex as 0. This is equivalent to connecting an imaginary source to every vertex with an edge of weight 0, so negative cycles in disconnected components can also be detected.
Relax every edge V - 1 times. For each edge [u, v, w], if: dist[u] + w < dist[v] then update dist[v].
After V - 1 iterations, perform one additional traversal of all edges. If any edge can still be relaxed, the graph contains a negative weight cycle. We can also stop early if an iteration performs no update.
Let us understand with an example: Input: V = 4, E = 4, edges[][] = [[1, 0, 4], [3, 1, -2], [1, 2, -6], [2, 3, 5]]
Initially, dist = [0, 0, 0, 0].
After 1st iteration, dist = [0, -2, -8, -3].
After 2nd iteration, dist = [0, -5, -11, -6].
After 3rd iteration, dist = [-1, -8, -14, -9].
During the final check, 3 -> 1 can still be relaxed because dist[3] - 2 = -11 < -8, so a negative cycle exists and the function returns true.
C++
#include<iostream>#include<vector>usingnamespacestd;boolisNegativeWeightCycle(intV,vector<vector<int>>&edges){vector<int>dist(V,0);// Relax all edges V - 1 times.for(inti=0;i<V-1;i++){boolupdated=false;for(constauto&edge:edges){intu=edge[0];intv=edge[1];intw=edge[2];if(dist[u]+w<dist[v]){dist[v]=dist[u]+w;updated=true;}}// No update means distances have stabilized.if(!updated){returnfalse;}}// Check whether any edge can still be relaxed.for(constauto&edge:edges){intu=edge[0];intv=edge[1];intw=edge[2];if(dist[u]+w<dist[v]){returntrue;}}returnfalse;}intmain(){intV1=4;vector<vector<int>>edges1={{0,3,6},{1,0,4},{1,2,6},{3,1,2}};cout<<(isNegativeWeightCycle(V1,edges1)?"true":"false")<<"\n";intV2=4;vector<vector<int>>edges2={{1,0,4},{3,1,-2},{1,2,-6},{2,3,5}};cout<<(isNegativeWeightCycle(V2,edges2)?"true":"false")<<"\n";return0;}
Java
classGFG{staticbooleanisNegativeWeightCycle(intV,int[][]edges){int[]dist=newint[V];// Relax all edges V - 1 times.for(inti=0;i<V-1;i++){booleanupdated=false;for(int[]edge:edges){intu=edge[0];intv=edge[1];intw=edge[2];if(dist[u]+w<dist[v]){dist[v]=dist[u]+w;updated=true;}}// No update means distances have stabilized.if(!updated){returnfalse;}}// Check whether any edge can still be relaxed.for(int[]edge:edges){intu=edge[0];intv=edge[1];intw=edge[2];if(dist[u]+w<dist[v]){returntrue;}}returnfalse;}publicstaticvoidmain(String[]args){intV1=4;int[][]edges1={{0,3,6},{1,0,4},{1,2,6},{3,1,2}};System.out.println(isNegativeWeightCycle(V1,edges1));intV2=4;int[][]edges2={{1,0,4},{3,1,-2},{1,2,-6},{2,3,5}};System.out.println(isNegativeWeightCycle(V2,edges2));}}
Python
defisNegativeWeightCycle(V:int,edges:list[list[int]])->bool:dist=[0]*V# Relax all edges V - 1 times.for_inrange(V-1):updated=Falseforu,v,winedges:ifdist[u]+w<dist[v]:dist[v]=dist[u]+wupdated=True# No update means distances have stabilized.ifnotupdated:returnFalse# Check whether any edge can still be relaxed.foru,v,winedges:ifdist[u]+w<dist[v]:returnTruereturnFalseif__name__=="__main__":V1=4edges1=[[0,3,6],[1,0,4],[1,2,6],[3,1,2]]print(str(isNegativeWeightCycle(V1,edges1)).lower())V2=4edges2=[[1,0,4],[3,1,-2],[1,2,-6],[2,3,5]]print(str(isNegativeWeightCycle(V2,edges2)).lower())
C#
usingSystem;classGFG{staticboolisNegativeWeightCycle(intV,int[,]edges){int[]dist=newint[V];intE=edges.GetLength(0);// Relax all edges V - 1 times.for(inti=0;i<V-1;i++){boolupdated=false;for(intj=0;j<E;j++){intu=edges[j,0];intv=edges[j,1];intw=edges[j,2];if(dist[u]+w<dist[v]){dist[v]=dist[u]+w;updated=true;}}// No update means distances have stabilized.if(!updated){returnfalse;}}// Check whether any edge can still be relaxed.for(inti=0;i<E;i++){intu=edges[i,0];intv=edges[i,1];intw=edges[i,2];if(dist[u]+w<dist[v]){returntrue;}}returnfalse;}staticvoidMain(){intV1=4;int[,]edges1={{0,3,6},{1,0,4},{1,2,6},{3,1,2}};Console.WriteLine(isNegativeWeightCycle(V1,edges1).ToString().ToLower());intV2=4;int[,]edges2={{1,0,4},{3,1,-2},{1,2,-6},{2,3,5}};Console.WriteLine(isNegativeWeightCycle(V2,edges2).ToString().ToLower());}}
JavaScript
functionisNegativeWeightCycle(V,edges){constdist=newArray(V).fill(0);// Relax all edges V - 1 times.for(leti=0;i<V-1;i++){letupdated=false;for(const[u,v,w]ofedges){if(dist[u]+w<dist[v]){dist[v]=dist[u]+w;updated=true;}}// No update means distances have stabilized.if(!updated){returnfalse;}}// Check whether any edge can still be relaxed.for(const[u,v,w]ofedges){if(dist[u]+w<dist[v]){returntrue;}}returnfalse;}// Driver CodeconstV1=4;constedges1=[[0,3,6],[1,0,4],[1,2,6],[3,1,2]];console.log(isNegativeWeightCycle(V1,edges1));constV2=4;constedges2=[[1,0,4],[3,1,-2],[1,2,-6],[2,3,5]];console.log(isNegativeWeightCycle(V2,edges2));