Find the ordering of tasks from given dependencies

02 Jun, 2022
There are a total of n tasks you have to pick, labeled from 0 to n-1. Some tasks may have prerequisites tasks, for example to pick task 0 you have to first finish tasks 1, which is expressed as a pair: [0, 1] Given the total number of tasks and a list of prerequisite pairs, return the ordering of tasks you should pick to finish all tasks. There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all tasks, return an empty array. Examples:
Input: 2, [[1, 0]] Output: [0, 1] Explanation: There are a total of 2 tasks to pick. To pick task 1 you should have finished task 0. So the correct task order is [0, 1] . Input: 4, [[1, 0], [2, 0], [3, 1], [3, 2]] Output: [0, 1, 2, 3] or [0, 2, 1, 3] Explanation: There are a total of 4 tasks to pick. To pick task 3 you should have finished both tasks 1 and 2. Both tasks 1 and 2 should be pick after you finished task 0. So one correct task order is [0, 1, 2, 3]. Another correct ordering is [0, 2, 1, 3].
Asked In: Google, Twitter, Amazon and many more companies. Solution: We can consider this problem as a graph (related to topological sorting) problem. All tasks are nodes of the graph and if task u is a prerequisite of task v, we will add a directed edge from node u to node v. Now, this problem is equivalent to finding a topological ordering of nodes/tasks (using topological sorting) in the graph represented by prerequisites. If there is a cycle in the graph, then it is not possible to finish all tasks (because in that case there is no any topological order of tasks). Both BFS and DFS can be used for topological sorting to solve it. Since pair is inconvenient for the implementation of graph algorithms, we first transform it to a graph. If task u is a prerequisite of task v, we will add a directed edge from node u to node v. Topological Sorting using BFS Here we use Kahn’s algorithm for topological sorting. BFS uses the indegrees of each node. We will first try to find a node with 0 indegree. If we fail to do so, there must be a cycle in the graph and we return false. Otherwise we have found one. We set its indegree to be -1 to prevent from visiting it again and reduce the indegrees of all its neighbors by 1. This process will be repeated for n (number of nodes) times. 
CPP
Java
// CPP program to find order to process tasks// so that all tasks can be finished. This program// mainly uses Kahn's algorithm.#include <bits/stdc++.h>using namespace std; // Returns adjacency list representation of graph from// given set of pairs.vector<unordered_set<int> > make_graph(int numTasks,             vector<pair<int, int> >& prerequisites){    vector<unordered_set<int> > graph(numTasks);    for (auto pre : prerequisites)        graph[pre.second].insert(pre.first);    return graph;} // Computes in-degree of every vertexvector<int> compute_indegree(vector<unordered_set<int> >& graph){    vector<int> degrees(graph.size(), 0);    for (auto neighbors : graph)        for (int neigh : neighbors)            degrees[neigh]++;    return degrees;} // main function for topological sortingvector<int> findOrder(int numTasks,        vector<pair<int, int> >& prerequisites){    // Create an adjacency list    vector<unordered_set<int> > graph =            make_graph(numTasks, prerequisites);     // Find vertices of zero degree    vector<int> degrees = compute_indegree(graph);    queue<int> zeros;    for (int i = 0; i < numTasks; i++)        if (!degrees[i])            zeros.push(i);     // Find vertices in topological order    // starting with vertices of 0 degree    // and reducing degrees of adjacent.    vector<int> toposort;    for (int i = 0; i < numTasks; i++) {        if (zeros.empty())            return {};        int zero = zeros.front();        zeros.pop();        toposort.push_back(zero);        for (int neigh : graph[zero]) {            if (!--degrees[neigh])                zeros.push(neigh);        }    }    return toposort;} // Driver codeint main(){    int numTasks = 4;    vector<pair<int, int> > prerequisites;     // for prerequisites: [[1, 0], [2, 1], [3, 2]]     prerequisites.push_back(make_pair(1, 0));    prerequisites.push_back(make_pair(2, 1));    prerequisites.push_back(make_pair(3, 2));    vector<int> v = findOrder(numTasks, prerequisites);     for (int i = 0; i < v.size(); i++) {        cout << v[i] << " ";    }     return 0;}
// Java program to find order to process tasks// so that all tasks can be finished. This program// mainly uses Kahn's algorithm. import java.util.ArrayList;import java.util.HashSet;import java.util.LinkedList;import java.util.Queue; public class Dep {     // Returns adjacency list representation of graph from    // given set of pairs.    static ArrayList<HashSet<Integer> >    make_graph(int numTasks, int[][] prerequisites)    {        ArrayList<HashSet<Integer> > graph            = new ArrayList<HashSet<Integer>>(numTasks);        for (int i = 0; i < numTasks; i++)            graph.add(new HashSet<Integer>());        for (int[] pre : prerequisites)            graph.get(pre[1]).add(pre[0]);        return graph;    }     // Computes in-degree of every vertex    static int[] compute_indegree(        ArrayList<HashSet<Integer> > graph)    {        int[] degrees = new int[graph.size()];        for (HashSet<Integer> neighbors : graph)            for (int neigh : neighbors)                degrees[neigh]++;        return degrees;    }     // main function for topological sorting    static ArrayList<Integer>    findOrder(int numTasks, int[][] prerequisites)    {        // Create an adjacency list        ArrayList<HashSet<Integer> > graph            = make_graph(numTasks, prerequisites);         // Find vertices of zero degree        int[] degrees = compute_indegree(graph);        Queue<Integer> zeros = new LinkedList<Integer>();        for (int i = 0; i < numTasks; i++)            if (degrees[i] == 0)                zeros.add(i);         // Find vertices in topological order        // starting with vertices of 0 degree        // and reducing degrees of adjacent.        ArrayList<Integer> toposort            = new ArrayList<Integer>();        for (int i = 0; i < numTasks; i++) {            if (zeros.isEmpty())                return new ArrayList<Integer>();            int zero = zeros.peek();            zeros.poll();            toposort.add(zero);            for (int neigh : graph.get(zero)) {                if (--degrees[neigh] == 0)                    zeros.add(neigh);            }        }        return toposort;    }     // Driver code    public static void main(String[] args)    {        int numTasks = 4;        int[][] prerequisites            = { { 1, 0 }, { 2, 1 }, { 3, 2 } };         ArrayList<Integer> v            = findOrder(numTasks, prerequisites);         for (int i = 0; i < v.size(); i++) {            System.out.print(v.get(i) + " ");        }    }} // This code is contributed by Lovely Jain
0 1 2 3
Topological Sorting using DFS: In this implementation, we use DFS based algorithm for Topological Sort. 
CPP
Java
// CPP program to find Topological sorting using// DFS#include <bits/stdc++.h>using namespace std;   // Returns adjacency list representation of graph from// given set of pairs.vector<unordered_set<int> > make_graph(int numTasks,             vector<pair<int, int> >& prerequisites){    vector<unordered_set<int> > graph(numTasks);    for (auto pre : prerequisites)        graph[pre.second].insert(pre.first);    return graph;}   // Does DFS and adds nodes to Topological Sortbool dfs(vector<unordered_set<int> >& graph, int node,            vector<bool>& onpath, vector<bool>& visited,                                 vector<int>& toposort){    if (visited[node])        return false;    onpath[node] = visited[node] = true;    for (int neigh : graph[node])        if (onpath[neigh] || dfs(graph, neigh, onpath, visited, toposort))            return true;    toposort.push_back(node);    return onpath[node] = false;}   // Returns an order of tasks so that all tasks can be// finished.vector<int> findOrder(int numTasks, vector<pair<int, int> >& prerequisites){    vector<unordered_set<int> > graph = make_graph(numTasks, prerequisites);    vector<int> toposort;    vector<bool> onpath(numTasks, false), visited(numTasks, false);    for (int i = 0; i < numTasks; i++)        if (!visited[i] && dfs(graph, i, onpath, visited, toposort))            return {};    reverse(toposort.begin(), toposort.end());    return toposort;}   int main(){    int numTasks = 4;    vector<pair<int, int> > prerequisites;       // for prerequisites: [[1, 0], [2, 1], [3, 2]]    prerequisites.push_back(make_pair(1, 0));    prerequisites.push_back(make_pair(2, 1));    prerequisites.push_back(make_pair(3, 2));    vector<int> v = findOrder(numTasks, prerequisites);       for (int i = 0; i < v.size(); i++) {        cout << v[i] << " ";    }       return 0;}
// Java program to find Topological sorting using// DFS import java.util.ArrayList;import java.util.Collections;import java.util.HashSet; public class Dfs1 {     // Returns adjacency list representation of graph from    // given set of pairs.    static ArrayList<HashSet<Integer> >    make_graph(int numTasks, int[][] prerequisites)    {        ArrayList<HashSet<Integer> > graph            = new ArrayList(numTasks);        for (int i = 0; i < numTasks; i++)            graph.add(new HashSet<Integer>());        for (int[] pre : prerequisites)            graph.get(pre[1]).add(pre[0]);        return graph;    }     // Does DFS and adds nodes to Topological Sort    static boolean dfs(ArrayList<HashSet<Integer> > graph,                       int node, boolean[] onpath,                       boolean[] visited,                       ArrayList<Integer> toposort)    {        if (visited[node])            return false;        onpath[node] = visited[node] = true;        for (int neigh : graph.get(node))            if (onpath[neigh]                || dfs(graph, neigh, onpath, visited,                       toposort))                return true;        toposort.add(node);        return onpath[node] = false;    }     // Returns an order of tasks so that all tasks can be    // finished.    static ArrayList<Integer>    findOrder(int numTasks, int[][] prerequisites)    {        ArrayList<HashSet<Integer> > graph            = make_graph(numTasks, prerequisites);        ArrayList<Integer> toposort            = new ArrayList<Integer>();        boolean[] onpath = new boolean[numTasks];        boolean[] visited = new boolean[numTasks];        for (int i = 0; i < numTasks; i++)            if (!visited[i]                && dfs(graph, i, onpath, visited, toposort))                return new ArrayList<Integer>();        Collections.reverse(toposort);        return toposort;    }     // Driver code    public static void main(String[] args)    {        int numTasks = 4;        int[][] prerequisites            = { { 1, 0 }, { 2, 1 }, { 3, 2 } };         ArrayList<Integer> v            = findOrder(numTasks, prerequisites);         for (int i = 0; i < v.size(); i++) {            System.out.print(v.get(i) + " ");        }    }} // This code is contributed by Lovely Jain
0 1 2 3
Reference: https://leetcode.com/problems/course-schedule-ii/
jainlovely450
BFS
DFS
Technical Scripter 2018
Topological Sorting
Graph
Technical Scripter
DFS
Graph
BFS
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Dijkstra's shortest path algorithm | Greedy Algo-7
Find if there is a path between two vertices in a directed graph
Kruskal’s Minimum Spanning Tree Algorithm | Greedy Algo-2
Detect Cycle in a Directed Graph
Introduction to Data Structures
Find if there is a path between two vertices in an undirected graph
What is Data Structure: Types, Classifications and Applications
Bellman–Ford Algorithm | DP-23
Minimum number of swaps required to sort an array
m Coloring Problem | Backtracking-5