Open In App

Print completed tasks at end according to Dependencies

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

Given N dependencies of the form X Y, where X & Y represents two different tasks. The dependency X Y denotes dependency of the form Y -> X i.e, if task Y happens then task X will happen in other words task Y has to be completed first to initiate task X. Also given M tasks that will initiate first. The task is to print all the tasks that will get completed at the end in the lexicographical order
Note that the tasks will be represented by upper case English letters only.

Input: dep[][] = {{A, B}, {C, B}, {D, A}, {D, C}, {B, E}}, tasks[] = {B, C} 
Output: A B C D Task A happens after task B and task D can only happen after the completion of tasks A or C. So, the required order is A B C D. 
Input: dep[][] = {{Q, P}, {S, Q}, {Q, R}}, tasks[] = {R} 
Output: Q R S

Approach: DFS can be used to solve the problem. The dependencies of the form X Y (Y -> X) can be represented as an edge from node Y to node X in the graph. Initiate the DFS from each of the M initial nodes and mark the nodes that are encountered as visited using a boolean array. At last, print the nodes/tasks that are covered using DFS in lexicographical order. The approach works because DFS will cover all the nodes starting from the initial nodes in sequential manner. Consider the diagram below that represents the first example from the above:
  
The diagram shows the edges covered during DFS from initial tasks B and C as Red in color. The nodes thus visited were A, B, C and D. Below is the implementation of the above approach: 

C++




// C++ implementation of the approach
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
 
// Graph class represents a directed graph
// using adjacency list representation
class Graph {
 
    // Number of vertices
    int V;
 
    // Pointer to an array containing
    // adjacency lists
    vector<int>* adj;
 
    // Boolean array to mark tasks as visited
    bool visited[26];
 
    // A recursive function used by DFS
    void DFSUtil(int v);
 
public:
    // Constructor
    Graph()
    {
 
        // There are only 26 English
        // upper case letters
        this->V = 26;
        adj = new vector<int>[26];
    }
 
    // Function to add an edge to the graph
    void addEdge(char v, char w);
 
    // DFS traversal of the vertices
    // reachable from v
    void DFS(char start[], int M);
 
    void printTasks();
};
 
// Function to add an edge to the graph
void Graph::addEdge(char v, char w)
{
 
    // Add w to v's list
    adj[v - 65].push_back(w - 65);
}
 
void Graph::DFSUtil(int v)
{
 
    // Mark the current node as visited and
    // print it
    visited[v] = true;
 
    // Recur for all the vertices adjacent
    // to this vertex
    vector<int>::iterator i;
    for (i = adj[v].begin(); i != adj[v].end(); ++i)
        if (!visited[*i])
            DFSUtil(*i);
}
 
// DFS traversal of the vertices reachable
// from start nodes
// It uses recursive DFSUtil()
void Graph::DFS(char start[], int M)
{
    // Mark all the vertices as not visited
    for (int i = 0; i < V; i++)
        visited[i] = false;
 
    // Call the recursive helper function
    // to print DFS traversal
    for (int i = 0; i < M; i++)
        DFSUtil(start[i] - 65);
}
 
// Helper function to print the tasks in
// lexicographical order that are completed
// at the end of the DFS
void Graph::printTasks()
{
    for (int i = 0; i < 26; i++) {
        if (visited[i])
            cout << char(i + 65) << " ";
    }
    cout << endl;
}
 
// Driver code
int main()
{
    // Create the graph
    Graph g;
    g.addEdge('B', 'A');
    g.addEdge('B', 'C');
    g.addEdge('A', 'D');
    g.addEdge('C', 'D');
    g.addEdge('E', 'B');
 
    // Initial tasks to be run
    char start[] = { 'B', 'C' };
    int n = sizeof(start) / sizeof(char);
 
    // Start the dfs
    g.DFS(start, n);
 
    // Print the tasks that will get finished
    g.printTasks();
 
    return 0;
}


Java




// Java implementation of the approach
import java.util.ArrayList;
import java.util.List;
 
public class Graph {
 
  // Number of vertices
  int V;
 
  // Pointer to an array containing
  // adjacency lists
  List<Integer>[] adj;
 
  // Boolean array to mark tasks as visited
  boolean[] visited;
 
  // A recursive function used by DFS
  void DFSUtil(int v)
  {
 
    // Mark the current node as visited and
    // print it
    visited[v] = true;
 
    // Recur for all the vertices adjacent
    // to this vertex
    List<Integer> list = adj[v];
    for (int node : list) {
      if (!visited[node])
        DFSUtil(node);
    }
  }
 
  // Constructor
  Graph()
  {
 
    // There are only 26 English
    // upper case letters
    this.V = 26;
    adj = new ArrayList[26];
    for (int i = 0; i < 26; i++)
      adj[i] = new ArrayList<Integer>();
  }
 
  // Function to add an edge to the graph
  void addEdge(char v, char w)
  {
 
    // Add w to v's list
    adj[v - 65].add(w - 65);
  }
 
  // DFS traversal of the vertices
  // reachable from start nodes
  void DFS(char start[], int M)
  {
 
    // Mark all the vertices as not visited
    visited = new boolean[26];
    for (int i = 0; i < 26; i++)
      visited[i] = false;
 
    // Call the recursive helper function
    // to print DFS traversal
    for (int i = 0; i < M; i++)
      DFSUtil(start[i] - 65);
  }
 
  // Helper function to print the tasks in
  // lexicographical order that are completed
  // at the end of the DFS
  void printTasks()
  {
    for (int i = 0; i < 26; i++) {
      if (visited[i])
        System.out.print((char)(i + 65) + " ");
    }
    System.out.println();
  }
 
  public static void main(String[] args)
  {
 
    // Create the graph
    Graph g = new Graph();
    g.addEdge('B', 'A');
    g.addEdge('B', 'C');
    g.addEdge('A', 'D');
    g.addEdge('C', 'D');
    g.addEdge('E', 'B');
 
    // Initial tasks to be run
    char start[] = { 'B', 'C' };
    int n = start.length;
 
    // Start the dfs
    g.DFS(start, n);
 
    // Print the tasks that will get finished
    g.printTasks();
  }
}
 
// This code is contributed by ishankhandelwals.


Python3




# Python3 implementation of the approach
from collections import defaultdict
 
# This class represents a directed graph
# using adjacency list representation
class Graph:
 
    # Constructor
    def __init__(self):
 
        # Default dictionary to store the graph
        self.graph = defaultdict(list)
        self.visited = [False]*26
 
    # Function to add an edge to the graph
    def addEdge(self, u, v):
        self.graph[ord(u)-65].append(ord(v)-65)
 
    # A function used by DFS
    def DFSUtil(self, v):
         
        # Mark the current node as visited
        # and print it
        self.visited[v]= True
 
        # Recur for all the vertices adjacent
        # to this vertex
        for i in self.graph[v]:
            if self.visited[i] == False:
                self.DFSUtil(i)
 
 
    # Function to perform the DFS traversal
    # It uses recursive DFSUtil()
    def DFS(self, start, M):
         
        # Total vertices
        V = len(self.graph)
         
        # Call the recursive helper function
        # to print the DFS traversal starting
        # from all vertices one by one
        for i in range(M):
            self.DFSUtil(ord(start[i])-65)
     
    def printOrder(self):
        for i in range(26):
            if self.visited[i] == True:
                print(chr(i + 65), end =" ")
        print("\n")
 
# Driver code
g = Graph()
g.addEdge('B', 'A')
g.addEdge('B', 'C')
g.addEdge('A', 'D')
g.addEdge('C', 'D')
g.addEdge('E', 'B')
 
g.DFS(['B', 'C'], 2)
g.printOrder()


Javascript




// JavaScript implementation of the approach
class Graph {
 
    // Number of vertices
    constructor() {
        this.V = 26;
        this.adj = new Array(26).fill([]);
        this.visited = new Array(26).fill(false);
    }
 
    // Function to add an edge to the graph
    addEdge(v, w) {
        // Add w to v's list
        this.adj[v.charCodeAt(0)-65].push(w.charCodeAt(0) - 65);
    }
 
    // A recursive function used by DFS
    DFSUtil(v) {
 
        // Mark the current node as visited and
        // print it
        this.visited[v] = true;
 
        // Recur for all the vertices adjacent
        // to this vertex
        for (let i = 0; i < this.adj[v].length; i++)
            if (!this.visited[this.adj[v][i]])
                this.DFSUtil(this.adj[v][i]);
    }
 
    // DFS traversal of the vertices reachable
    // from start nodes
    // It uses recursive DFSUtil()
    DFS(start, M) {
        // Mark all the vertices as not visited
        for (let i = 0; i < this.V; i++)
            this.visited[i] = false;
 
        // Call the recursive helper function
        // to print DFS traversal
        for (let i = 0; i < M; i++)
            this.DFSUtil(start[i].charCodeAt(0) - 65);
    }
 
    // Helper function to print the tasks in
    // lexicographical order that are completed
    // at the end of the DFS
    printTasks() {
        for (let i = 0; i < 26; i++) {
            if (this.visited[i])
                console.log(String.fromCharCode(i + 65) + " ");
        }
        console.log("\n");
    }
}
 
// Driver code
let g = new Graph();
g.addEdge('B', 'A');
g.addEdge('B', 'C');
g.addEdge('A', 'D');
g.addEdge('C', 'D');
g.addEdge('E', 'B');
 
// Initial tasks to be run
let start = ['B', 'C'];
let n = start.length;
 
// Start the dfs
g.DFS(start, n);
 
// Print the tasks that will get finished
g.printTasks();
 
// This code is contributed by ishankhandelwals.


C#




using System;
using System.Collections.Generic;
 
class Graph
{
    // Number of vertices
    private int V = 26;
 
    // Adjacency list to store the graph
    private List<int>[] adj;
 
    // Boolean array to mark tasks as visited
    private bool[] visited = new bool[26];
 
    // Constructor
    public Graph()
    {
        adj = new List<int>[26];
        for (int i = 0; i < 26; i++)
        {
            adj[i] = new List<int>();
        }
    }
 
    // Function to add an edge to the graph
    public void AddEdge(char v, char w)
    {
        adj[v - 65].Add(w - 65);
    }
 
    // Recursive function used by DFS
    private void DFSUtil(int v)
    {
        visited[v] = true;
 
        foreach (int i in adj[v])
        {
            if (!visited[i])
            {
                DFSUtil(i);
            }
        }
    }
 
    // DFS traversal of the vertices reachable from start nodes
    public void DFS(char[] start)
    {
        // Mark all the vertices as not visited
        for (int i = 0; i < V; i++)
        {
            visited[i] = false;
        }
 
        // Call the recursive helper function for DFS traversal
        foreach (char c in start)
        {
            DFSUtil(c - 65);
        }
    }
 
    // Helper function to print the tasks in lexicographical order
    public void PrintTasks()
    {
        for (int i = 0; i < 26; i++)
        {
            if (visited[i])
            {
                Console.Write((char)(i + 65) + " ");
            }
        }
        Console.WriteLine();
    }
}
 
class Program
{
    static void Main(string[] args)
    {
        // Create the graph
        Graph g = new Graph();
        g.AddEdge('B', 'A');
        g.AddEdge('B', 'C');
        g.AddEdge('A', 'D');
        g.AddEdge('C', 'D');
        g.AddEdge('E', 'B');
 
        // Initial tasks to be run
        char[] start = { 'B', 'C' };
 
        // Start the DFS
        g.DFS(start);
 
        // Print the tasks that will get finished
        g.PrintTasks();
    }
}


Output:

A B C D

Time Complexity: O(V + E) where V is the number of nodes in the graph and E is the number of edges or dependencies. In this case, since V is always 26, so the time complexity is O(26 + E) or just O(E) in the worst case. 
Space Complexity: O(V + E)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads