Given a directed graph with N nodes and M edges determine if there exists a negative cycle in the graph. If a negative cycle exists print “YES” and output any vertex sequence that forms the cycle; otherwise print “NO”.
Examples:
Input:
4 5
1 2 1
2 4 1
3 1 1
4 1 -3
4 3 -2
Output:
YES
1 2 4 1
Approach:
To determine if there exists a negative cycle in the graph we can use the Shortest Path Faster Algorithm. We perform the relaxation on the all edges repeatedly for the n-1 iterations where n is the number of the nodes. If on the nth iteration we still find a relaxation and it indicates the presence of the negative cycle.
Step-by-step approach:
- Use Shortest Path Faster Algorithm to find whether there is a negative weighted cycle in the graph or not.
- While relaxing the nodes, maintain a parent array, say par[] which stores the parent of the node which we have relaxed.
- If there is a negative weighted cycle in the graph, then print all the nodes in the cycle using the parent array.
- If no cycle is present, simply print NO.
Below is the implementation of the algorithm:
C++
#include <bits/stdc++.h>
#define ll long long int
#define INF 1000000000000000
#define pb push_back
using namespace std;
// Adjacency List to store the weighted graph
vector<pair<ll, ll> > graph[2501];
// array to store the distance to any node
ll dist[2501];
// array to store the parent of any node
ll par[2501];
// array to store the number of time a node has been relaxed
ll cnt[2501];
ll n, m, u, v, w, q;
// array to keep track of whether a node is already in the
// queue
bool in_queue[2501];
// array to keep track of visited nodes
bool visited[2501];
ll x;
// Function to run Shortest Path Fast Algorithm
bool spfa(ll start)
{
// Initialize the distance of starting node = 0
dist[start] = 0;
// Initialize the parent of starting node = -1
par[start] = -1;
// Queue to run SPFA
queue<ll> q;
// Push the starting node in the queue
q.push(start);
in_queue[start] = true;
while (!q.empty()) {
// Pop the front element of the queue
ll ele = q.front();
visited[ele] = true;
in_queue[ele] = false;
q.pop();
// Iterate over all the children of the current node
for (auto child : graph[ele]) {
// If the distance to the child node is greater
// than the distance of the current node + edge
// weight, then relax the child node
if (dist[child.first]
> dist[ele] + child.second) {
// Incrment the relaxation count of the
// child node
cnt[child.first]++;
// If the child has been relaxed more than n
// times, then there is a cycle
if (cnt[child.first] > n) {
x = child.first;
par[child.first] = ele;
return false;
}
// Update the minimum distance to the child
// node
dist[child.first]
= dist[ele] + child.second;
// Push the child node if it is already not
// in queue
if (!in_queue[child.first]) {
q.push(child.first);
in_queue[child.first] = true;
}
// Update the parent of the child node with
// the current node
par[child.first] = ele;
}
}
}
return true;
}
int main()
{
n = 4, m = 5;
// Initialize the distance to all nodes as INF
for (int i = 0; i <= n; i++)
dist[i] = INF;
vector<vector<ll> > edges = { { 1, 2, 1 },
{ 2, 4, 1 },
{ 3, 1, 1 },
{ 4, 1, -3 },
{ 4, 3, -2 } };
for (ll i = 0; i < m; i++) {
graph[edges[i][0]].push_back(
{ edges[i][1], edges[i][2] });
}
for (ll i = 1; i <= n; i++) {
// If there is a negative weight cycle in the graph
if (!spfa(i)) {
cout << "YES" << endl;
ll ele = x;
stack<ll> st;
bool is_stack[2501] = {};
// Push all the elements in the stack using the
// parent array
while (!is_stack[ele]) {
is_stack[ele] = true;
st.push(ele);
ele = par[ele];
}
// Print all the nodes in the negative weight
// cycle
cout << ele << " ";
while (st.top() != ele) {
cout << st.top() << " ";
st.pop();
}
cout << ele << endl;
return 0;
}
}
cout << "NO" << endl;
}
Java
import java.util.*;
public class SPFA {
static final long INF = 1000000000000000L;
static int MAX_N = 2501;
// Adjacency List to store the weighted graph
static List<Pair>[] graph = new ArrayList[MAX_N];
// array to store the distance to any node
static long[] dist = new long[MAX_N];
// array to store the parent of any node
static int[] par = new int[MAX_N];
// array to store the number of times a node has been
// relaxed
static int[] cnt = new int[MAX_N];
static int n, m, u, v, w, q;
// array to keep track of whether a node is already in
// the queue
static boolean[] in_queue = new boolean[MAX_N];
// array to keep track of visited nodes
static boolean[] visited = new boolean[MAX_N];
static int x;
public static void main(String[] args)
{
n = 4;
m = 5;
// Initialize the distance to all nodes as INF
Arrays.fill(dist, INF);
for (int i = 0; i <= n; i++) {
graph[i] = new ArrayList<>();
}
long[][] edges = { { 1, 2, 1 },
{ 2, 4, 1 },
{ 3, 1, 1 },
{ 4, 1, -3 },
{ 4, 3, -2 } };
for (long[] edge : edges) {
graph[(int)edge[0]].add(
new Pair((int)edge[1], edge[2]));
}
for (int i = 1; i <= n; i++) {
// If there is a negative weight cycle in the
// graph
if (!spfa(i)) {
System.out.println("YES");
int ele = x;
Stack<Integer> stack = new Stack<>();
boolean[] is_stack = new boolean[MAX_N];
// Push all the elements in the stack using
// the parent array
while (!is_stack[ele]) {
is_stack[ele] = true;
stack.push(ele);
ele = par[ele];
}
// Print all the nodes in the negative
// weight cycle
System.out.print(ele + " ");
while (stack.peek() != ele) {
System.out.print(stack.pop() + " ");
}
System.out.println(ele);
return;
}
}
System.out.println("NO");
}
// Function to run Shortest Path Fast Algorithm
static boolean spfa(int start)
{
// Initialize the distance of starting node = 0
dist[start] = 0;
// Initialize the parent of starting node = -1
par[start] = -1;
// Queue to run SPFA
Queue<Integer> q = new LinkedList<>();
// Push the starting node in the queue
q.add(start);
in_queue[start] = true;
while (!q.isEmpty()) {
// Pop the front element of the queue
int ele = q.poll();
visited[ele] = true;
in_queue[ele] = false;
// Iterate over all the children of the current
// node
for (Pair child : graph[ele]) {
// If the distance to the child node is
// greater than the distance of the current
// node + edge weight, then relax the child
// node
if (dist[child.first]
> dist[ele] + child.second) {
// Increment the relaxation count of the
// child node
cnt[child.first]++;
// If the child has been relaxed more
// than n times, then there is a cycle
if (cnt[child.first] > n) {
x = child.first;
par[child.first] = ele;
return false;
}
// Update the minimum distance to the
// child node
dist[child.first]
= dist[ele] + child.second;
// Push the child node if it is already
// not in queue
if (!in_queue[child.first]) {
q.add(child.first);
in_queue[child.first] = true;
}
// Update the parent of the child node
// with the current node
par[child.first] = ele;
}
}
}
return true;
}
// Helper class to represent pairs
static class Pair {
int first;
long second;
Pair(int first, long second)
{
this.first = first;
this.second = second;
}
}
}
// This code is contributed by Ayush Mishra
Python
from collections import deque
INF = 10**18
# Adjacency List to store the weighted graph
graph = [[] for _ in range(2501)]
# array to store the distance to any node
dist = [INF] * 2501
# array to store the parent of any node
par = [-1] * 2501
# array to store the number of times a node has been relaxed
cnt = [0] * 2501
n, m = 4, 5
# Function to run Shortest Path Fast Algorithm
def spfa(start):
global n
# Initialize the distance of starting node = 0
dist[start] = 0
# Initialize the parent of starting node = -1
par[start] = -1
# Queue to run SPFA
q = deque()
# Push the starting node in the queue
q.append(start)
while q:
# Pop the front element of the queue
ele = q.popleft()
# Iterate over all the children of the current node
for child, weight in graph[ele]:
# If the distance to the child node is greater
# than the distance of the current node + edge
# weight, then relax the child node
if dist[child] > dist[ele] + weight:
# Increment the relaxation count of the
# child node
cnt[child] += 1
# If the child has been relaxed more than n
# times, then there is a cycle
if cnt[child] > n:
return False, child
# Update the minimum distance to the child
# node
dist[child] = dist[ele] + weight
# Push the child node if it is not already
# in queue
if child not in q:
q.append(child)
# Update the parent of the child node with
# the current node
par[child] = ele
return True, -1
edges = [[1, 2, 1],
[2, 4, 1],
[3, 1, 1],
[4, 1, -3],
[4, 3, -2]]
# Create the graph from the given edges
for u, v, w in edges:
graph[u].append((v, w))
# Check for negative weight cycle using SPFA
for i in range(1, n + 1):
has_cycle, cycle_node = spfa(i)
if not has_cycle:
print("YES")
ele = cycle_node
st = []
is_stack = [False] * 2501
# Push all the elements in the stack using the
# parent array
while not is_stack[ele]:
is_stack[ele] = True
st.append(ele)
ele = par[ele]
# Print all the nodes in the negative weight
# cycle
print(ele, end=" ")
while st[-1] != ele:
print(st.pop(), end=" ")
print(ele)
break
else:
print("NO")
JavaScript
const INF = 1000000000000000;
// Adjacency List to the store the weighted graph
let graph = Array.from({ length: 2501 }, () => []);
let dist = Array.from({ length: 2501 }, () => INF);
let par = Array.from({ length: 2501 }, () => -1);
let cnt = Array.from({ length: 2501 }, () => 0);
let n = 4, m = 5;
let x;
function spfa(start) {
// Initialize the distance of the starting node = 0
dist[start] = 0;
// Initialize the parent of the starting node = -1
par[start] = -1;
// Queue to run SPFA
let q = [];
let inQueue = Array.from({ length: 2501 }, () => false);
// Push the starting node in the queue
q.push(start);
inQueue[start] = true;
while (q.length > 0) {
// Pop the front element of the queue
let ele = q.shift();
inQueue[ele] = false;
// Iterate over all the children of the current node
for (let i = 0; i < graph[ele].length; i++) {
let child = graph[ele][i];
if (dist[child[0]] > dist[ele] + child[1]) {
cnt[child[0]]++;
if (cnt[child[0]] > n) {
x = child[0];
par[child[0]] = ele;
return false;
}
// Update the minimum distance to the child
// node
dist[child[0]] = dist[ele] + child[1];
// Push the child node if it is already not
// in queue
if (!inQueue[child[0]]) {
q.push(child[0]);
inQueue[child[0]] = true;
}
// Update the parent of the child node with
// the current node
par[child[0]] = ele;
}
}
}
return true;
}
// Example usage
let edges = [[1, 2, 1], [2, 4, 1], [3, 1, 1], [4, 1, -3], [4, 3, -2]];
for (let i = 0; i < m; i++) {
graph[edges[i][0]].push([edges[i][1], edges[i][2]]);
}
for (let i = 1; i <= n; i++) {
// If there is a negative weight cycle in the graph
if (!spfa(i)) {
console.log("YES");
let ele = x;
let st = [];
let isStack = Array.from({ length: 2501 }, () => false);
// Push all the elements in the stack using the
// parent array
while (!isStack[ele]) {
isStack[ele] = true;
st.push(ele);
ele = par[ele];
}
process.stdout.write(ele + " ");
while (st[st.length - 1] !== ele) {
process.stdout.write(st.pop() + " ");
}
console.log(ele);
process.exit();
}
}
console.log("NO");
Time Complexity: O(n * m) Auxiliary Space: O(n)
|