# Check if it is possible to finish all task from given dependencies (Course Schedule I)

There are a total of N tasks, labeled from 0 to N-1. Some tasks may have prerequisites, for example to do task 0 you have to first complete task 1, which is expressed as a pair: [0, 1]. Given the total number of tasks N and a list of prerequisite pairs P, find if it is possible to finish all tasks.

Examples:

Input: N = 4, P = 3, prerequisites = {{1,0},{2,1},{3,2}}
Output: Yes
Explanation: To do task 1 you should have completed task 0, and to do task 2 you should have finished task 1, and to do task 3 you should have finished task 2. So it is possible.

Input: N = 2, P = 2, prerequisites = {{1,0},{0,1}}
Output: No
Explanation: To do task 1 you should have completed task 0, and to do task 0 you should have finished task 1. So it is impossible.

Recommended Practice

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 detecting a cycle 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 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.

Prerequisite: Detect Cycle in a Directed Graph

## Check if it is possible to finish all task from given dependenciesusing DFS:

For DFS, it will first visit a node, then one neighbor of it, then one neighbor of this neighbor… and so on. If it meets a node which was visited in the current process of DFS visit, a cycle is detected and we will return false. Otherwise it will start from another unvisited node and repeat this process till all the nodes have been visited. Note that you should make two records: one is to record all the visited nodes and the other is to record the visited nodes in the current DFS visit.

Step by step approach:

• We use a vector visited to record all the visited nodes and another vector onpath to record the visited nodes of the current DFS visit.
• Start the DFS from a node which has not been visited once.
• During the DFS, if we encounter a node which was visited in the current DFS visit, then return false as we have got a cycle in the graph.
• Once the current visit is finished, we reset the onpath value of the nodes which were visited in the current DFS to false.
• If no cycle is found, return true.

Below is the implementation of the above approach:

## CPP

## Java

## Python3

## C#

## Javascript

Output

Time Complexity: O(V*(V+E)), where V is the number of vertices and E is the number of edges.
Auxiliary Space: O(V+E)

## Check if it is possible to finish all task from given dependencies using Topological Sort:

If we perform a topological sort and all the nodes get visited, then it means there is no cycle and it is possible to finish all the tasks. If any of the node is unvisited, it means that particular node is dependent on another node which in turn is dependent on some other node and so on. So, we cannot finish those tasks because of circular dependency.

Step by step approach:

• Calculate the indegree of all the nodes of the graph.
• Start by pushing all the nodes with indegree 0 into a queue and start traversing by popping elements from the queue.
• Whenever we pop a node, we decrease indegree of all its neighboring nodes by 1 and if indegree of any of the neighboring nodes becomes 0, then we push that neighboring node into our queue.
• Continue the above steps till our queue becomes empty.
• Now, check if all the nodes are visited. If yes, return true, else return false.

Below is the implementation of the above approach:

## C++

## Java

## Python3

 from collections import deque  class Solution:    # Main function to check whether it's     # possible to finish all tasks or not    def canFinish(self, numTasks, prerequisites):        graph = [[] for _ in range(numTasks)]        inDegree = [0] * numTasks         # Initialize the graph and in-degrees        for edge in prerequisites:            graph[edge[0]].append(edge[1])            inDegree[edge[1]] += 1         queue = deque()         # Push all the nodes with no dependencies         # (in-degree = 0) into the queue        for i in range(numTasks):            if inDegree[i] == 0:                queue.append(i)         while queue:            node = queue.popleft()             # Reduce the in-degree of all neighbors by 1            for neighbor in graph[node]:                inDegree[neighbor] -= 1                 # Push the neighboring node if we have                 # covered all its dependencies (in-degree = 0)                if inDegree[neighbor] == 0:                    queue.append(neighbor)         # Check if there is a node whose in-degree is not zero        for i in range(numTasks):            if inDegree[i] != 0:                return False         return True  # Test the functionnumTasks = 4prerequisites = [    [1, 0],    [2, 1],    [3, 2]] solution = Solution()if solution.canFinish(numTasks, prerequisites):    print("Possible to finish all tasks")else:    print("Impossible to finish all tasks")

## C#

## Javascript

 function canFinish(numTasks, prerequisites) {    const graph = new Array(numTasks).fill().map(() => []);    const inDegree = new Array(numTasks).fill(0);     // Construct the graph and initialize the indegree of nodes    prerequisites.forEach((edge) => {        graph[edge[0]].push(edge[1]);        inDegree[edge[1]] += 1;    });     const q = [];     // Push all the nodes with no dependencies (indegree = 0)    for (let i = 0; i < numTasks; i++) {        if (inDegree[i] === 0) {            q.push(i);        }    }     while (q.length > 0) {        const node = q.shift();         // Reduce the indegree of all neighbors by 1        for (const child of graph[node]) {            inDegree[child] -= 1;             // Push the neighboring node if we have covered            // all its dependencies (indegree = 0)            if (inDegree[child] === 0) {                q.push(child);            }        }    }     // Check if there is a node whose indegree is not zero    for (let i = 0; i < numTasks; i++) {        if (inDegree[i] !== 0) {            return false;        }    }     return true;} // Main programconst numTasks = 4;const prerequisites = [    [1, 0],    [2, 1],    [3, 2]]; if (canFinish(numTasks, prerequisites)) {    console.log("Possible to finish all tasks");} else {    console.log("Impossible to finish all tasks");}

Output

Time Complexity: O(V+E), where V is the number of vertices and E is the number of edges.
Auxiliary Space: O(V)

Previous
Next