Open In App

Maximum edges that can be added to DAG so that it remains DAG

Last Updated : 28 Feb, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

A DAG is given to us, we need to find maximum number of edges that can be added to this DAG, after which new graph still remain a DAG that means the reformed graph should have maximal number of edges, adding even single edge will create a cycle in graph.

Maximum edges that can be added to DAG so that it remains DAG

The Output for above example should be following edges in any order.
4-2, 4-5, 4-3, 5-3, 5-1, 2-0, 2-1, 0-3, 0-1

As shown in above example, we have added all the edges in one direction only to save ourselves from making a cycle. This is the trick to solve this question. We sort all our nodes in topological order and create edges from node to all nodes to the right if not there already. 
How can we say that, it is not possible to add any more edge? the reason is we have added all possible edges from left to right and if we want to add more edge we need to make that from right to left, but adding edge from right to left we surely create a cycle because its counter part left to right edge is already been added to graph and creating cycle is not what we needed. 
So solution proceeds as follows, we consider the nodes in topological order and if any edge is not there from left to right, we will create it. 

Below is the solution, we have printed all the edges that can be added to given DAG without making any cycle. 

C++




// C++ program to find maximum edges after adding
// which graph still remains a DAG
#include <bits/stdc++.h>
using namespace std;
 
class Graph {
    int V; // No. of vertices
 
    // Pointer to a list containing adjacency list
    list<int>* adj;
 
    // Vector to store indegree of vertices
    vector<int> indegree;
 
    // function returns a topological sort
    vector<int> topologicalSort();
 
public:
    Graph(int V); // Constructor
 
    // function to add an edge to graph
    void addEdge(int v, int w);
 
    // Prints all edges that can be added without making any
    // cycle
    void maximumEdgeAddition();
};
 
//  Constructor of graph
Graph::Graph(int V)
{
    this->V = V;
    adj = new list<int>[V];
 
    // Initialising all indegree with 0
    for (int i = 0; i < V; i++)
        indegree.push_back(0);
}
 
//  Utility function to add edge
void Graph::addEdge(int v, int w)
{
    adj[v].push_back(w); // Add w to v's list.
 
    // increasing inner degree of w by 1
    indegree[w]++;
}
 
//  Main function to print maximum edges that can be added
vector<int> Graph::topologicalSort()
{
    vector<int> topological;
    queue<int> q;
 
    //  In starting push all node with indegree 0
    for (int i = 0; i < V; i++)
        if (indegree[i] == 0)
            q.push(i);
 
    while (!q.empty()) {
        int t = q.front();
        q.pop();
 
        //  push the node into topological vector
        topological.push_back(t);
 
        //  reducing indegree of adjacent vertices
        for (list<int>::iterator j = adj[t].begin();
             j != adj[t].end(); j++) {
            indegree[*j]--;
 
            //  if indegree becomes 0, just push
            // into queue
            if (indegree[*j] == 0)
                q.push(*j);
        }
    }
    return topological;
}
 
//  The function prints all edges that can be
//  added without making any cycle
//  It uses recursive topologicalSort()
void Graph::maximumEdgeAddition()
{
    bool* visited = new bool[V];
    vector<int> topo = topologicalSort();
 
    //  looping for all nodes
    for (int i = 0; i < topo.size(); i++) {
        int t = topo[i];
 
        //  In below loop we mark the adjacent node of t
        for (list<int>::iterator j = adj[t].begin();
             j != adj[t].end(); j++)
            visited[*j] = true;
 
        //  In below loop unmarked nodes are printed
        for (int j = i + 1; j < topo.size(); j++) {
            // if not marked, then we can make an edge
            // between t and j
            if (!visited[topo[j]])
                cout << t << "-" << topo[j] << " ";
 
            visited[topo[j]] = false;
        }
    }
}
 
// Driver code to test above methods
int main()
{
    // Create a graph given in the above diagram
    Graph g(6);
    g.addEdge(5, 2);
    g.addEdge(5, 0);
    g.addEdge(4, 0);
    g.addEdge(4, 1);
    g.addEdge(2, 3);
    g.addEdge(3, 1);
 
    g.maximumEdgeAddition();
    return 0;
}


Java




// Java program to find maximum edges after adding
// which graph still remains a DAG
import java.util.*;
 
public class Graph {
 
  int V;   // No. of vertices
 
  ArrayList<ArrayList<Integer>> adj;  // adjacency list
 
  // array to store indegree of vertices
  int[] indegree;
 
  //  Constructor of graph
  Graph(int v)
  {
    this.V = v;
    indegree = new int[V];
    adj = new ArrayList<>(V);
 
    for(int i = 0; i < V; i++)
    {
      adj.add(new ArrayList<Integer>());
      indegree[i] = 0;
    }
  }
 
  //  Utility function to add edge
  public void addEdge(int v,int w)
  {
    adj.get(v).add(w);// Add w to v's list.
 
    // increasing inner degree of w by 1
    indegree[w]++;
  }
 
  //  Main function to print maximum edges that can be added
  public List<Integer> topologicalSort() 
  {
 
    List<Integer> topological = new ArrayList<>(V);
    Queue<Integer> q = new LinkedList<>();
 
    //  In starting push all node with indegree 0
    for(int i = 0; i < V; i++)
    {
      if(indegree[i] == 0)
      {
        q.add(i);
      }
    }
 
 
    while(!q.isEmpty())
    {
      int t=q.poll();
 
      //  push the node into topological list
      topological.add(t);
 
      //  reducing inDegree of adjacent vertical       
      for(int j: adj.get(t))
      {
        indegree[j]--;
 
        //  if inDegree becomes 0, just push
        // into queue
        if(indegree[j] == 0)
        {
          q.add(j);
        }
      }
 
    }
 
    return topological;
 
  }
 
  //  The function prints all edges that can be
  //  added without making any cycle
  //  It uses recursive topologicalSort()
  public void maximumEdgeAddition()
  {
    boolean[] visited = new boolean[V];
    List<Integer> topo=topologicalSort();
 
    //  looping for all nodes
    for(int i = 0; i < topo.size(); i++)
    {
      int t = topo.get(i);
 
      //  In below loop we mark the adjacent node of t
      for( Iterator<Integer> j = adj.get(t).listIterator();j.hasNext();)
      {
        visited[j.next()] = true;
      }
 
      for(int j = i + 1; j < topo.size(); j++)
      {
        // if not marked, then we can make an edge
        // between t and j
        if(!visited[topo.get(j)])
        {
          System.out.print( t  + "-" + topo.get(j) + " ");
        }
 
        visited[topo.get(j)] = false;
      }
    }
  }
 
  // Driver code to test above methods
  public static void main(String[] args)
  {    
 
    // Create a graph given in the above diagram
    Graph g = new Graph(6);
    g.addEdge(5, 2);
    g.addEdge(5, 0);
    g.addEdge(4, 0);
    g.addEdge(4, 1);
    g.addEdge(2, 3);
    g.addEdge(3, 1);
 
    g.maximumEdgeAddition();
    return ;
  }   
}
 
// This code is contributed by sameergupta22.


Python3




# Python3 program to find maximum
# edges after adding which graph
# still remains a DAG
 
 
class Graph:
 
    def __init__(self, V):
 
        # No. of vertices
        self.V = V
 
        # Pointer to a list containing
        # adjacency list
        self.adj = [[] for i in range(V)]
 
        # Vector to store indegree of vertices
        self.indegree = [0 for i in range(V)]
 
    # Utility function to add edge
    def addEdge(self, v, w):
 
         # Add w to v's list.
        self.adj[v].append(w)
 
        # Increasing inner degree of w by 1
        self.indegree[w] += 1
 
    # Main function to print maximum
    # edges that can be added
    def topologicalSort(self):
 
        topological = []
        q = []
 
        # In starting append all node
        # with indegree 0
        for i in range(self.V):
            if (self.indegree[i] == 0):
                q.append(i)
 
        while (len(q) != 0):
            t = q[0]
            q.pop(0)
 
            # Append the node into topological
            # vector
            topological.append(t)
 
            # Reducing indegree of adjacent
            # vertices
            for j in self.adj[t]:
                self.indegree[j] -= 1
 
                # If indegree becomes 0, just
                # append into queue
                if (self.indegree[j] == 0):
                    q.append(j)
 
        return topological
 
    # The function prints all edges that
    # can be added without making any cycle
    # It uses recursive topologicalSort()
    def maximumEdgeAddition(self):
 
        visited = [False for i in range(self.V)]
 
        topo = self.topologicalSort()
 
        # Looping for all nodes
        for i in range(len(topo)):
            t = topo[i]
 
            # In below loop we mark the
            # adjacent node of t
            for j in self.adj[t]:
                visited[j] = True
 
            # In below loop unmarked nodes
            # are printed
            for j in range(i + 1, len(topo)):
 
                # If not marked, then we can make
                # an edge between t and j
                if (not visited[topo[j]]):
                    print(str(t) + '-' +
                          str(topo[j]), end=' ')
 
                visited[topo[j]] = False
 
 
# Driver code
if __name__ == '__main__':
 
    # Create a graph given in the
    # above diagram
    g = Graph(6)
    g.addEdge(5, 2)
    g.addEdge(5, 0)
    g.addEdge(4, 0)
    g.addEdge(4, 1)
    g.addEdge(2, 3)
    g.addEdge(3, 1)
 
    g.maximumEdgeAddition()
 
# This code is contributed by rutvik_56


C#




// C# program to find maximum edges after Adding
// which graph still remains a DAG
 
using System;
using System.Collections.Generic;
 
public class Graph {
    private int V; // No. of vertices
 
    private List<int>[] adj; // adjacency list
 
    // array to store indegree of vertices
    private int[] indegree;
 
    // Constructor of graph
    public Graph(int v)
    {
        V = v;
        indegree = new int[V];
        adj = new List<int>[ V ];
        for (int i = 0; i < V; i++) {
            adj[i] = new List<int>();
            indegree[i] = 0;
        }
    }
 
    // Utility function to Add edge
    public void AddEdge(int v, int w)
    {
        adj[v].Add(w); // Add w to v's list.
 
        // increasing inner degree of w by 1
        indegree[w]++;
    }
 
    // function to print maximum edges that can be Added
    public List<int> TopologicalSort()
    {
 
        List<int> topological = new List<int>();
        Queue<int> q = new Queue<int>();
 
        // In starting push all node with indegree 0
        for (int i = 0; i < V; i++) {
            if (indegree[i] == 0) {
                q.Enqueue(i);
            }
        }
 
        while (q.Count > 0) {
            int t = q.Dequeue();
 
            // push the node into topological list
            topological.Add(t);
 
            // reducing inDegree of adjacent vertical
            foreach(int j in adj[t])
            {
                indegree[j]--;
 
                // if inDegree becomes 0, just push
                // into queue
                if (indegree[j] == 0) {
                    q.Enqueue(j);
                }
            }
        }
 
        return topological;
    }
 
    // The function prints all edges that can be
    // Added without making any cycle
    // It uses recursive topologicalSort()
    public void MaximumEdgeAddition()
    {
        bool[] visited = new bool[V];
        List<int> topo = TopologicalSort();
 
        // looping for all nodes
        for (int i = 0; i < topo.Count; i++) {
            int t = topo[i];
 
            // In below loop we mark the adjacent node of t
            foreach(int j in adj[t]) { visited[j] = true; }
 
            for (int j = i + 1; j < topo.Count; j++) {
                // if not marked, then we can make an edge
                // between t and j
                if (!visited[topo[j]]) {
                    Console.Write(t + "-" + topo[j] + " ");
                }
 
                visited[topo[j]] = false;
            }
        }
        Console.WriteLine();
    }
 
    // Driver code to test above methods
    static void Main(string[] args)
    {
 
        // Create a graph given in the above diagram
        Graph g = new Graph(6);
        g.AddEdge(5, 2);
        g.AddEdge(5, 0);
        g.AddEdge(4, 0);
        g.AddEdge(4, 1);
        g.AddEdge(2, 3);
        g.AddEdge(3, 1);
 
        g.MaximumEdgeAddition();
    }
}
 
// This code is contributed by cavi4762.


Javascript




// javascript program to find maximum
// edges after adding which graph
// still remains a DAG
class Graph{
 
    constructor(V){
 
        // No. of vertices
        this.V = V
 
        // Pointer to a list containing
        // adjacency list
        this.adj = new Array(V);
        for(let i = 0; i < V; i++){
            this.adj[i] = new Array();
        }
         
        // Vector to store indegree of vertices
        this.indegree = new Array(V).fill(0);
    }
         
 
    // Utility function to add edge
    addEdge(v, w){
 
        // Add w to v's list.
        this.adj[v].push(w)
 
        // Increasing inner degree of w by 1
        this.indegree[w] += 1
    }
 
    // Main function to print maximum
    // edges that can be added
    topologicalSort(){
 
        let topological = new Array();
        let q = new Array();
 
        // In starting append all node
        // with indegree 0
        for(let i= 0; i < this.V; i++){
            if (this.indegree[i] == 0){
                q.push(i);
            }
                 
        }
 
        while (q.length != 0){
            let t = q[0];
            q.shift();
 
            // Append the node into topological
            // vector
            topological.push(t)
 
            // Reducing indegree of adjacent
            // vertices
            for(let indx = 0; indx < this.adj[t].length; indx++){
                let j = this.adj[t][indx];
                 
                this.indegree[j] -= 1;
                 
                // If indegree becomes 0, just
                // append into queue
                if (this.indegree[j] == 0){
                    q.push(j);
                }
            }
        }
 
        return topological;
    }
 
    // The function prints all edges that
    // can be added without making any cycle
    // It uses recursive topologicalSort()
    maximumEdgeAddition(){
 
        let visited = new Array(this.V).fill(false);
 
        let topo = this.topologicalSort();
 
        // Looping for all nodes
        for(let i = 0; i < topo.length; i++){
            let t = topo[i];
 
            // In below loop we mark the
            // adjacent node of t
            for(let indx = 0; indx < this.adj[t].length; indx++){
                let j = this.adj[t][indx];
                visited[j] = true;
            }
 
            // In below loop unmarked nodes
            // are printed
             
            for(let j = i+1; j < topo.length; j++){
 
                // If not marked, then we can make
                // an edge between t and j
                if (!visited[topo[j]]){
                    console.log(t.toString() + '-' + topo[j].toString() + ' ');
                }
 
                visited[topo[j]] = false;
            }
        }
    }
}
// Driver code
 
// Create a graph given in the
// above diagram
let g = new Graph(6);
g.addEdge(5, 2);
g.addEdge(5, 0);
g.addEdge(4, 0);
g.addEdge(4, 1);
g.addEdge(2, 3);
g.addEdge(3, 1);
 
g.maximumEdgeAddition();
 
// This code is contributed by gautam goel.


Output

4-5 4-2 4-3 5-3 5-1 2-0 2-1 0-3 0-1 

Time complexity : O(V + E) 

Space complexity : O(V + E) 

 

Optimized approach for finding only the number of edges that can be added

If we have to find only the maximum number of edges that can be added, it can be solved simply by understanding the following observation. If a DAG has n nodes, it has n nodes in it’s topological sort as well. The maximum number of edges a DAG can have can be determined by finding the maximum number of nodes that can be linked with each node. This implies the first node is connected to (n-1) nodes, the second node is connected to (n-2) nodes until the last node is not connected to any node. The reason for this decreasing pattern is because any edge from right node to the left node of the topological sort creates a cycle and it’ll no longer be a DAG. 

This means a DAG of n nodes can have a maximum number of
(n-1) + (n-2) + (n-3) + . . . 3 + 2 + 1 = n*(n-1)/2 edges

If the DAG already has E edges, then the maximum number of additional edges that can be added is given by (n*(n-1)/2 – E) which will be our final answer.

Below is the code implementation of the optimized approach

C++




#include <iostream>
using namespace std;
 
int max_edges(int V, int E)
{
      return V * (V - 1) / 2 - E;
}
 
int main()
{
    int V, E;
    // The number of vertices in the DAG
    V = 6;
    // The number of edges in the DAG
    E = 6;
      // Final output
    cout << "Maximum number of edges that can be added to maintain DAG is " << max_edges(V, E);
    return 0;
}


Python3




def max_edges(V,E):
    return V*(V-1)//2 - E
 
# The number of vertices in the DAG
V = 6
# The number of edges in the DAG
E = 6
# Final output
print("Maximum number of edges that can be added to maintain DAG is",max_edges(V,E))


Java




import java.io.*;
 
public class Main {
 
    static int max_edges(int V, int E) {
        return (V * (V - 1) / 2) - E;
    }
 
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
 
        int V, E;
        // The number of vertices in the DAG
        V = 6;
        // The number of edges in the DAG
        E = 6;
        // Final output
        System.out.println("Maximum number of edges that can be added to maintain DAG is " + max_edges(V, E));
    }
}


C#




using System;
 
class MainClass {
    static int MaxEdges(int V, int E) {
        return (V * (V - 1) / 2) - E;
    }
 
    public static void Main(string[] args) {
        int V, E;
        // The number of vertices in the DAG
        V = 6;
        // The number of edges in the DAG
        E = 6;
        // Final output
        Console.WriteLine("Maximum number of edges that can be added to maintain DAG is " + MaxEdges(V, E));
    }
}


Javascript




function maxEdges(V, E) {
    return (V * (V - 1) / 2) - E;
}
 
// The number of vertices in the DAG
const V = 6;
// The number of edges in the DAG
const E = 6;
// Final output
console.log(`Maximum number of edges that can be added to maintain DAG is ${maxEdges(V, E)}`);


Output

Maximum number of edges that can be added to maintain DAG is 9

Time Complexity: O(1)

Auxiliary Space: O(1)

NOTE: A DAG can have multiple topological sorting orders, but for each case, the maximum number of edges that can be added to maintain DAG remains same.



Previous Article
Next Article

Similar Reads

Assign directions to edges so that the directed graph remains acyclic
Given a graph with both directed and undirected edges. It is given that the directed edges don't form cycle. How to assign directions to undirected edges so that the graph (with all directed edges) remains acyclic even after the assignment? For example, in the below graph, blue edges don't have directions. We strongly recommend to minimize your bro
1 min read
Minimum edges to be added in a directed graph so that any node can be reachable from a given node
Given a directed graph and a node X. The task is to find the minimum number of edges that must be added to the graph such that any node can be reachable from the given node.Examples: Input: X = 0 Output: 3Input: X = 4 Output: 1 Approach: First, let's mark all the vertices reachable from X as good, using a simple DFS. Then, for each bad vertex (vert
10 min read
Maximum number of elements that can be removed such that MEX of the given array remains unchanged
Given an array arr[] of size N, the task is to count the maximum number of elements that can be removed from the given array without changing the MEX of the original array. The MEX is the smallest positive integer that is not present in the array. Examples: Input: arr[] = {2, 3, 5, 1, 6} Output: 2 Explanation:The smallest positive integer which is
6 min read
Maximum number of edges to be added to a tree so that it stays a Bipartite graph
A tree is always a Bipartite Graph as we can always break into two disjoint sets with alternate levels. In other words we always color it with two colors such that alternate levels have same color. The task is to compute the maximum no. of edges that can be added to the tree so that it remains Bipartite Graph. Examples: Input : Tree edges as vertex
6 min read
Minimum number of edges that need to be added to form a triangle
Given an undirected graph with N vertices and N edges. No two edges connect the same pair of vertices. A triangle is a set of three distinct vertices such that each pair of those vertices is connected by an edge i.e. three distinct vertices u, v and w are a triangle if the graph contains the edges (u, v), (v, w) and (v, u). The task is to find the
9 min read
Minimum number of Edges to be added to a Graph to satisfy the given condition
Given a graph consisting of N nodes numbered from 0 to N - 1 and M edges in the form of pairs {a, b}, the task is to find the minimum number of edges to be added to the graph such that if there exists a path from any node a to node b, then there should be paths from node a to nodes [ a + 1, a + 2, a + 3, ..., b - 1] as well. Examples: Input: N = 7,
12 min read
Maximize number of edges added to convert given Tree into a Bipartite Graph
Given a tree of N nodes, the task is to find the maximum number of edges that can be added to the tree such that it becomes a bipartite graph. Note: Self loop or multiple edges are not allowed but cycles are permitted. Examples: Input: N = 4, Edges = {{1, 2}, {2, 3}, {1, 4}} 1 / \ 2 4 / 3Output: 1Explanation: An edge between nodes 3 and 4 can be ad
13 min read
Ways to Remove Edges from a Complete Graph to make Odd Edges
Given a complete graph with N vertices, the task is to count the number of ways to remove edges such that the resulting graph has odd number of edges. Examples: Input: N = 3 Output: 4 The initial graph has 3 edges as it is a complete graph. We can remove edges (1, 2) and (1, 3) or (1, 2) and (2, 3) or (1, 3) and (2, 3) or we do not remove any of th
4 min read
Pendant Vertices, Non-Pendant Vertices, Pendant Edges and Non-Pendant Edges in Graph
Pre-requisites: Handshaking theorem. Pendant Vertices Let G be a graph, A vertex v of G is called a pendant vertex if and only if v has degree 1. In other words, pendant vertices are the vertices that have degree 1, also called pendant vertex. Note: Degree = number of edges connected to a vertex In the case of trees, a pendant vertex is known as a
7 min read
Find maximum height to cut all chocolates horizontally such that at least K amount remains
Given an array arr[] consisting of heights of N chocolate bars, the task is to find the maximum height at which the horizontal cut is made to all the chocolates such that the sum remaining amount of chocolate is at least K. Examples: Input: K = 7, arr[] = [15, 20, 8, 17]Output: 15Explanation:Suppose a cut is made at height 8:-&gt; chocolate taken f
10 min read
Practice Tags :