Open In App

Count Edge reversal in a Directed Graph

Last Updated : 31 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a directed graph with n nodes from 0 to n-1, a 2d array edges[][] where edges[i] = [ui, vi] represents a directed edge going from node ui to node vi . The graph would form a tree if its edges were bi-directional, the task is to find the minimum edge direction reversals required for each node such that there is a directed path from that node to all other nodes. Return the array where ith index represents the minimum edge reversals required from that particular to reach all other nodes.

Examples:

Input: n = 4, edges = {{2, 0}, {2, 1}, {1, 3}}
Output: [1, 1, 0, 2]
Explanation:

Screenshot-2023-11-10-at-101240-PM-200

Example-1

  1. For node 0 the edge between the 0 and 2 should be reversed to reach every node so 1.
  2. For node 1 the edge between the 1 and 2 should be reversed to reach every node so 1.
  3. For node 2 already all nodes are reachable from node 2 so 0For node 3 the edge between the 3 to 1 and 1 to. 2 should be reversed so 2.

Input: n = 3, edges = {{1, 2}, {2, 0}}
Output: [2, 0, 1]
Explanation:

Screenshot-2023-11-10-at-110751-PM-200

Example-2

  1. For node 0 the edge between the 1 and 2 should be reverse to reach every node so 2.
  2. For node 1 already all nodes are reachable from node 1 so 0.
  3. For node 2 the edge between the 2 and 1 should be reversed to reach every node so 1.

Naive Approach: The basic way to solve the problem is as follows:

In this approach the problem can be solve by counting the number of edges to reversed for each node , first for a edge u->v the reversal required is 0 but for from v to u it requires 1 reversal during initializing the graph for each mark the reversal for opposite direction to 1 and the same direction to 0 using a dp array , then do DFS for each node to all other nodes and then keep adding the dp[node] then the dp array will be our answer.

Time Complexity: O(n*n) where n is the number of nodes
Auxiliary Space: O(n) where n is the number of nodes

Efficient approach: To solve the problem follow the below idea:

  • In this approach we only compute the total reversals required for one node to reach all other nodes by maintaing another array also for number of reversals required to reach some node x from the root node and also maintaining another array for storing the depth of each node from root node. From only one DFS call we maintain these arrays and the total reversals required for the root node reach all the nodes.
  • Using the depth we can find the reversals required in reverse direction for example the number of revesals from node x to node y is m ,the reversals required for going from node y to node x is depth from root – m. Using this logic we can compute the reversals required to discover all other nodes using one DFS only for root node and maintaing the depth and reversal required to reach all other nodes.
  • Like the final equation to find the reversals required to reach node x to all other nodes is :
  • Suppose the reversals required to for root node to all other nodes is totalReversals , the depth of node x from root node is d and number of reversals is r .
  • Since we know using the DFS we have computed the totalReversals from root node , suppose from any node x using (d-r) reversals we can reach root node from root node we can reach all other nodes by using the totalReversals – r (that is excluding the number of reversals required to reach node x )
  • So the reversals for any node x to reach all other nodes , the answer be like :
  • depth – reversals required to reach node x from root + total reversals for root node – number of reversals to reach node x from root

Follow these steps to solve the above approach:

  • Initialize the res array to store the result, depth array to store the depth of root i from the root node, visited array to keep track of visited nodes,edgeRev array to keep track of number of reversals required to reach node i from the root node, graph , and totalReversals to 0.
  • Construct the graph along with the reversal count which is 0 for u-> v and 1 for v-> u.
  • Start the DFS from the node 0 and compute the depth, edgeRev arrays and the totalReversals required for node 0 to reach all the node.
  • After the DFS ,assign the total reversals to the root node 0.
  • For each node compute the total reversals by iterating from 0 to n.
  • Count the reversals from the node i to root, Count the reversals from the root i to remaining nodes and add them and assing to res[i].
  • Return the result.

Implementation of the above approach:

C++




// C++ code for the above appraoch:
#include <bits/stdc++.h>
using namespace std;
 
// Function to perform DFS on root node
void DFS(int node, int par,
         unordered_map<int, vector<pair<int, int> > > graph,
         vector<bool>& visited, vector<int>& edgeRev, int d,
         vector<int>& depth, int& totalReversals)
{
 
    // Mark the node as vsisited
    visited[node] = true;
    // Assign the depth of the node
    depth[node] = d;
    // Iterate throgh the child and
    // explore the child
    for (auto child : graph[node]) {
        if (!visited[child.first]) {
 
            // Sum up the reversal required to
            // reach the child from the root node
            edgeRev[child.first]
                = edgeRev[node] + child.second;
 
            // Add the reversals until now
            totalReversals += child.second;
 
            // Perform the DFS on teh child
            DFS(child.first, node, graph, visited, edgeRev,
                d + 1, depth, totalReversals);
        }
    }
}
// Function to find the minimum edge reversals
// required for each node to raech all other nodes
vector<int>
minimumEdgeReversals(int n, vector<vector<int> >& edges)
{
 
    // Initialize the res array to store the
    // result, depth array to store the depth of
    // root i from the root node, visited array
    // to keep track of visited nodes, edgeRev
    // array to keep track of number of reversals
    // required to reach node i from the root
    // node, graph, and totalReversals to 0.
    vector<int> res(n, 0);
    vector<int> depth(n, 0);
    vector<bool> visited(n, false);
    vector<int> edgeRev(n, 0);
    int totalReversals = 0;
    unordered_map<int, vector<pair<int, int> > > graph;
    // Start from the node 0
    int startNode = 0;
    // Construct the graph along with the
    // reversal count which is 0 for
    // u-> v and 1 for v-> u.
    for (auto edge : edges) {
        int u = edge[0], v = edge[1];
        graph[u].push_back({ v, 0 });
        graph[v].push_back({ u, 1 });
    }
 
    // Start the DFS from the node 0.
    DFS(startNode, -1, graph, visited, edgeRev, 0, depth,
        totalReversals);
 
    // Assign the total reversals to
    // the root node 0.
    res[startNode] = totalReversals;
    // For each node compute the total reversals
    for (int i = 0; i < n; i++) {
        if (i == startNode)
            continue;
 
        // Count the reversals from the
        // node i to root
 
        int xToRootRev = depth[i] - edgeRev[i];
 
        // Count the reversals from the root
        // i to remaining nodes
        int rootToRem = totalReversals - edgeRev[i];
 
        // Add the sum
        res[i] = xToRootRev + rootToRem;
    }
 
    // Return the result
    return res;
}
// Driver code
int main()
{
 
    int n = 4;
    vector<vector<int> > edges
        = { { 2, 0 }, { 2, 1 }, { 1, 3 } };
    vector<int> res = minimumEdgeReversals(n, edges);
 
    for (int i = 0; i < res.size(); i++) {
        cout << res[i] << " ";
    }
 
    return 0;
}


Java




import java.util.*;
 
class EdgeReversals {
    // Function to perform DFS on the root node
    static void DFS(int node, int par, Map<Integer, List<Pair<Integer, Integer>>> graph,
            boolean[] visited, int[] edgeRev, int d, int[] depth, int[] totalReversals) {
 
        // Mark the node as visited
        visited[node] = true;
        // Assign the depth of the node
        depth[node] = d;
        // Iterate through the child and
        // explore the child
        for (Pair<Integer, Integer> child : graph.get(node)) {
            if (!visited[child.getKey()]) {
 
                // Sum up the reversal required to
                // reach the child from the root node
                edgeRev[child.getKey()] = edgeRev[node] + child.getValue();
 
                // Add the reversals until now
                totalReversals[0] += child.getValue();
 
                // Perform DFS on the child
                DFS(child.getKey(), node, graph, visited, edgeRev, d + 1, depth, totalReversals);
            }
        }
    }
 
    // Function to find the minimum edge reversals
    // required for each node to reach all other nodes
    static int[] minimumEdgeReversals(int n, int[][] edges) {
 
        // Initialize the res array to store the
        // result, depth array to store the depth of
        // root i from the root node, visited array
        // to keep track of visited nodes, edgeRev
        // array to keep track of the number of reversals
        // required to reach node i from the root
        // node, graph, and totalReversals to 0.
        int[] res = new int[n];
        int[] depth = new int[n];
        boolean[] visited = new boolean[n];
        int[] edgeRev = new int[n];
        int[] totalReversals = {0};
        Map<Integer, List<Pair<Integer, Integer>>> graph = new HashMap<>();
        // Start from the node 0
        int startNode = 0;
        // Construct the graph along with the
        // reversal count which is 0 for
        // u -> v and 1 for v -> u.
        for (int[] edge : edges) {
            int u = edge[0], v = edge[1];
            graph.computeIfAbsent(u, k -> new ArrayList<>()).add(new Pair<>(v, 0));
            graph.computeIfAbsent(v, k -> new ArrayList<>()).add(new Pair<>(u, 1));
        }
 
        // Start the DFS from the node 0.
        DFS(startNode, -1, graph, visited, edgeRev, 0, depth, totalReversals);
 
        // Assign the total reversals to
        // the root node 0.
        res[startNode] = totalReversals[0];
        // For each node, compute the total reversals
        for (int i = 0; i < n; i++) {
            if (i == startNode)
                continue;
 
            // Count the reversals from the
            // node i to the root
 
            int xToRootRev = depth[i] - edgeRev[i];
 
            // Count the reversals from the root
            // i to remaining nodes
            int rootToRem = totalReversals[0] - edgeRev[i];
 
            // Add the sum
            res[i] = xToRootRev + rootToRem;
        }
 
        // Return the result
        return res;
    }
 
    // Driver code
    public static void main(String[] args) {
 
        int n = 4;
        int[][] edges = { { 2, 0 }, { 2, 1 }, { 1, 3 } };
        int[] res = minimumEdgeReversals(n, edges);
 
        for (int i = 0; i < res.length; i++) {
            System.out.print(res[i] + " ");
        }
    }
 
    static class Pair<K, V> {
        private final K key;
        private final V value;
 
        public Pair(K key, V value) {
            this.key = key;
            this.value = value;
        }
 
        public K getKey() {
            return key;
        }
 
        public V getValue() {
            return value;
        }
    }
}
 
// This code is contributed by rambabuguphka


Python3




from collections import defaultdict
 
# Function to perform Depth-First Search (DFS) on the root node
def DFS(node, par, graph, visited, edgeRev, d, depth, totalReversals):
    visited[node] = True
    depth[node] = d
 
    # Traverse through the children of the current node
    for child, value in graph[node]:
        if not visited[child]:
            # Update the reversal count for the child node
            edgeRev[child] = edgeRev[node] + value
            totalReversals[0] += value
            # Perform DFS on the child node
            DFS(child, node, graph, visited, edgeRev, d + 1, depth, totalReversals)
 
# Function to find the minimum edge reversals required for each node
def minimumEdgeReversals(n, edges):
    res = [0] *
    depth = [0] *
    visited = [False] *
    edgeRev = [0] *
    totalReversals = [0
    graph = defaultdict(list# Create an adjacency list representation using defaultdict
    startNode = 0  # Define the starting node for traversal
 
    # Create the graph representation from the given edges
    for edge in edges:
        u, v = edge
        graph[u].append((v, 0)) 
        graph[v].append((u, 1)) 
 
    # Perform DFS starting from the start node
    DFS(startNode, -1, graph, visited, edgeRev, 0, depth, totalReversals)
    res[startNode] = totalReversals[0# Set the total reversals for the starting node
 
    # Calculate the minimum edge reversals for each node
    for i in range(n):
        if i == startNode:
            continue
 
        xToRootRev = depth[i] - edgeRev[i]
        rootToRem = totalReversals[0] - edgeRev[i]
        res[i] = xToRootRev + rootToRem  # Compute the total reversals required for each node
 
    return res  # Return the result array containing minimum edge reversals for each node
 
# Driver code
if __name__ == "__main__":
    n = 4
    edges = [[2, 0], [2, 1], [1, 3]]
    res = minimumEdgeReversals(n, edges)
 
    # Display the minimum edge reversals for each node
    for i in range(len(res)):
        print(res[i], end=" ")


C#




using System;
using System.Collections.Generic;
 
public class GFG {
    // Function to perform DFS on root node
    static void
    DFS(int node, int par,
        Dictionary<int, List<KeyValuePair<int, int> > >
            graph,
        bool[] visited, int[] edgeRev, int d, int[] depth,
        ref int totalReversals)
    {
        // Mark the node as visited
        visited[node] = true;
        // Assign the depth of the node
        depth[node] = d;
        // Iterate through the children and explore them
        foreach(var child in graph[node])
        {
            if (!visited[child.Key]) {
                // Sum up the reversal required to reach the
                // child from the root node
                edgeRev[child.Key]
                    = edgeRev[node] + child.Value;
                // Add the reversals until now
                totalReversals += child.Value;
                // Perform the DFS on the child
                DFS(child.Key, node, graph, visited,
                    edgeRev, d + 1, depth,
                    ref totalReversals);
            }
        }
    }
 
    // Function to find the minimum edge reversals
    // required for each node to reach all other nodes
    static List<int>
    MinimumEdgeReversals(int n, List<List<int> > edges)
    {
        // Initialize the res array to store the result,
        // depth array to store the depth of root i from the
        // root node, visited array to keep track of visited
        // nodes, edgeRev array to keep track of number of
        // reversals required to reach node i from the root
        // node, graph, and totalReversals to 0.
        List<int> res = new List<int>(new int[n]);
        int[] depth = new int[n];
        bool[] visited = new bool[n];
        int[] edgeRev = new int[n];
        int totalReversals = 0;
        Dictionary<int, List<KeyValuePair<int, int> > >
            graph = new Dictionary<
                int, List<KeyValuePair<int, int> > >();
        // Start from the node 0
        int startNode = 0;
        // Construct the graph along with the
        // reversal count which is 0 for u->v and 1 for
        // v->u.
        foreach(var edge in edges)
        {
            int u = edge[0], v = edge[1];
            if (!graph.ContainsKey(u))
                graph[u]
                    = new List<KeyValuePair<int, int> >();
            if (!graph.ContainsKey(v))
                graph[v]
                    = new List<KeyValuePair<int, int> >();
            graph[u].Add(new KeyValuePair<int, int>(v, 0));
            graph[v].Add(new KeyValuePair<int, int>(u, 1));
        }
 
        // Start the DFS from the node 0
        DFS(startNode, -1, graph, visited, edgeRev, 0,
            depth, ref totalReversals);
 
        // Assign the total reversals to the root node 0
        res[startNode] = totalReversals;
        // For each node compute the total reversals
        for (int i = 0; i < n; i++) {
            if (i == startNode)
                continue;
 
            // Count the reversals from the node i to root
            int xToRootRev = depth[i] - edgeRev[i];
 
            // Count the reversals from the root i to
            // remaining nodes
            int rootToRem = totalReversals - edgeRev[i];
 
            // Add the sum
            res[i] = xToRootRev + rootToRem;
        }
 
        // Return the result
        return res;
    }
 
    // Driver code
    static public void Main()
    {
        int n = 4;
        List<List<int> > edges = new List<List<int> >() {
            new List<int>() { 2, 0 }, new List<int>() {
                2, 1
            }, new List<int>() { 1, 3 }
        };
        List<int> res = MinimumEdgeReversals(n, edges);
 
        foreach(var val in res)
        {
            Console.Write(val + " ");
        }
    }
}


Javascript




// javaScript code for the above approach
 
// Function to perform DFS on root node
function DFS(node, par, graph, visited, edgeRev, d, depth, totalReversals) {
    visited[node] = true;
    depth[node] = d;
 
    if (graph.has(node)) {
        for (const [child, val] of graph.get(node)) {
            if (!visited[child]) {
                edgeRev[child] = edgeRev[node] + val;
                totalReversals[0] += val;
 
                DFS(child, node, graph, visited, edgeRev, d + 1, depth, totalReversals);
            }
        }
    }
}
 
// Function to find the minimum edge reversals
// required for each node to raech all other nodes
function minimumEdgeReversals(n, edges) {
    // Initialize the res array to store the
    // result, depth array to store the depth of
    // root i from the root node, visited array
    // to keep track of visited nodes, edgeRev
    // array to keep track of number of reversals
    // required to reach node i from the root
    // node, graph, and totalReversals to 0.
    const res = Array(n).fill(0);
    const depth = Array(n).fill(0);
    const visited = Array(n).fill(false);
    const edgeRev = Array(n).fill(0);
    const totalReversals = [0];
    const graph = new Map();
 
    const startNode = 0;
 
    // Construct the graph along with the
    // reversal count which is 0 for
    // u-> v and 1 for v-> u.
    for (const [u, v] of edges) {
        if (!graph.has(u)) graph.set(u, []);
        if (!graph.has(v)) graph.set(v, []);
        graph.get(u).push([v, 0]);
        graph.get(v).push([u, 1]);
    }
 
    DFS(startNode, -1, graph, visited, edgeRev, 0, depth, totalReversals);
 
    // Assign the total reversals to
    // the root node 0.
    res[startNode] = totalReversals[0];
 
    // For each node compute the total reversals
    for (let i = 0; i < n; i++) {
        if (i === startNode) continue;
         
        // Count the reversals from the
        // node i to root
        const xToRootRev = depth[i] - edgeRev[i];
         
        // Count the reversals from the root
        // i to remaining nodes
        const rootToRem = totalReversals[0] - edgeRev[i];
         
        // add the sum
        res[i] = xToRootRev + rootToRem;
    }
     
    // return result
    return res;
}
 
// Driver Code
const n = 4;
const edges = [
    [2, 0],
    [2, 1],
    [1, 3]
];
const res = minimumEdgeReversals(n, edges);
console.log(res.join(" "));


Output

1 1 0 2 












Time Complexity: O(n) where n is the number of nodes.
Auxiliary Space: O(n) where n is the number of nodes.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads