There are a total of n tasks you have to pick, labelled from 0 to n-1. Some tasks may have prerequisites, for example to pick task 0 you have to first pick task 1, which is expressed as a pair: [0, 1]
Given the total number of tasks and a list of prerequisite pairs, is it possible for you to finish all tasks?
Examples:
Input: 2, [[1, 0]]
Output: true
Explanation: There are a total of 2 tasks to pick. To pick task 1 you should have finished task 0. So it is possible.
Input: 2, [[1, 0], [0, 1]]
Output: false
Explanation: There are a total of 2 tasks to pick. To pick task 1 you should have finished task 0, and to pick task 0 you should also have finished task 1. So it is impossible.
Input: 3, [[1, 0], [2, 1], [3, 2]]
Output: true
Explanation: There are a total of 3 tasks to pick. To pick tasks 1 you should have finished task 0, and to pick task 2 you should have finished task 1 and to pick task 3 you should have finished task 2. So it is possible.
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 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
Using 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.
The code is as follows. 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. Once the current visit is finished, we reset the onpath value of the starting node to false.
Implementation:
CPP
#include <bits/stdc++.h>
using namespace std;
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;
}
bool dfs_cycle(vector<unordered_set< int > >& graph, int node,
vector< bool >& onpath, vector< bool >& visited)
{
if (visited[node])
return false ;
onpath[node] = visited[node] = true ;
for ( int neigh : graph[node])
if (onpath[neigh] || dfs_cycle(graph, neigh, onpath, visited))
return true ;
return onpath[node] = false ;
}
bool canFinish( int numTasks, vector<pair< int , int > >& prerequisites)
{
vector<unordered_set< int > > graph = make_graph(numTasks, prerequisites);
vector< bool > onpath(numTasks, false ), visited(numTasks, false );
for ( int i = 0; i < numTasks; i++)
if (!visited[i] && dfs_cycle(graph, i, onpath, visited))
return false ;
return true ;
}
int main()
{
int numTasks = 4;
vector<pair< int , int > > prerequisites;
prerequisites.push_back(make_pair(1, 0));
prerequisites.push_back(make_pair(2, 1));
prerequisites.push_back(make_pair(3, 2));
if (canFinish(numTasks, prerequisites)) {
cout << "Possible to finish all tasks" ;
}
else {
cout << "Impossible to finish all tasks" ;
}
return 0;
}
|
Java
import java.util.*;
public class GFG{
static class pair{
int first, second;
pair( int first, int second){
this .first = first;
this .second = second;
}
}
static ArrayList<ArrayList<Integer>> make_graph( int numTasks,
Vector<pair> prerequisites)
{
ArrayList<ArrayList<Integer>> graph = new ArrayList<ArrayList<Integer>>(numTasks);
for ( int i= 0 ; i<numTasks; i++){
graph.add( new ArrayList<Integer>());
}
for (pair pre : prerequisites)
graph.get(pre.second).add(pre.first);
return graph;
}
static boolean dfs_cycle(ArrayList<ArrayList<Integer>> graph, int node,
boolean onpath[], boolean visited[])
{
if (visited[node])
return false ;
onpath[node] = visited[node] = true ;
for ( int neigh : graph.get(node))
if (onpath[neigh] || dfs_cycle(graph, neigh, onpath, visited))
return true ;
return onpath[node] = false ;
}
static boolean canFinish( int numTasks, Vector<pair> prerequisites)
{
ArrayList<ArrayList<Integer>> graph = make_graph(numTasks, prerequisites);
boolean onpath[] = new boolean [numTasks];
boolean visited[] = new boolean [numTasks];
for ( int i = 0 ; i < numTasks; i++)
if (!visited[i] && dfs_cycle(graph, i, onpath, visited))
return false ;
return true ;
}
public static void main(String args[])
{
int numTasks = 4 ;
Vector<pair> prerequisites = new Vector<pair>();;
prerequisites.add( new pair( 1 , 0 ));
prerequisites.add( new pair( 2 , 1 ));
prerequisites.add( new pair( 3 , 2 ));
if (canFinish(numTasks, prerequisites)) {
System.out.println( "Possible to finish all tasks" );
}
else {
System.out.println( "Impossible to finish all tasks" );
}
}
}
|
Python3
class pair:
def __init__( self , first, second):
self .first = first
self .second = second
def make_graph(numTasks, prerequisites):
graph = []
for i in range (numTasks):
graph.append([])
for pre in prerequisites:
graph[pre.second].append(pre.first)
return graph
def dfs_cycle(graph, node, onpath, visited):
if visited[node]:
return false
onpath[node] = visited[node] = True
for neigh in graph[node]:
if (onpath[neigh] or dfs_cycle(graph, neigh, onpath, visited)):
return true
return False
def canFinish(numTasks, prerequisites):
graph = make_graph(numTasks, prerequisites)
onpath = [ False ] * numTasks
visited = [ False ] * numTasks
for i in range (numTasks):
if ( not visited[i] and dfs_cycle(graph, i, onpath, visited)):
return False
return True
numTasks = 4
prerequisites = []
prerequisites.append(pair( 1 , 0 ))
prerequisites.append(pair( 2 , 1 ))
prerequisites.append(pair( 3 , 2 ))
if canFinish(numTasks, prerequisites):
print ( "Possible to finish all tasks" )
else :
print ( "Impossible to finish all tasks" )
|
C#
using System;
using System.Collections.Generic;
public class GFG {
public class pair {
public int first, second;
public pair( int first, int second)
{
this .first = first;
this .second = second;
}
}
static List<List< int > >
make_graph( int numTasks, List<pair> prerequisites)
{
List<List< int > > graph
= new List<List< int > >(numTasks);
for ( int i = 0; i < numTasks; i++) {
graph.Add( new List< int >());
}
foreach (pair pre in prerequisites) graph[pre.second]
.Add(pre.first);
return graph;
}
static bool dfs_cycle(List<List< int > > graph, int node,
bool [] onpath, bool [] visited)
{
if (visited[node])
return false ;
onpath[node] = visited[node] = true ;
foreach ( int neigh in graph[node])
if (onpath[neigh] || dfs_cycle(graph, neigh, onpath,
visited))
return true ;
return false ;
}
static bool canFinish( int numTasks,
List<pair> prerequisites)
{
List<List< int > > graph
= make_graph(numTasks, prerequisites);
bool [] onpath = new bool [numTasks];
bool [] visited = new bool [numTasks];
for ( int i = 0; i < numTasks; i++)
if (!visited[i]
&& dfs_cycle(graph, i, onpath, visited))
return false ;
return true ;
}
public static void Main(String[] args)
{
int numTasks = 4;
List<pair> prerequisites = new List<pair>();
;
prerequisites.Add( new pair(1, 0));
prerequisites.Add( new pair(2, 1));
prerequisites.Add( new pair(3, 2));
if (canFinish(numTasks, prerequisites)) {
Console.WriteLine(
"Possible to finish all tasks" );
}
else {
Console.WriteLine(
"Impossible to finish all tasks" );
}
}
}
|
Javascript
function make_graph(numTasks, prerequisites){
let graph = [];
for (let i = 0; i < numTasks; i++){
graph.push([]);
}
for (let i = 0; i < prerequisites.length; i++){
graph[prerequisites[i][1]].push(prerequisites[i][0]);
}
return graph;
}
function dfs_cycle(graph, node, onpath, visited){
if (visited[node])
return false ;
onpath[node] = visited[node] = true ;
for (let i = 0; i < graph[node].length; i++){
let neigh = graph[node][i];
if (onpath[neigh] == true || dfs_cycle(graph, neigh, onpath, visited) == true )
return true ;
}
return false ;
}
function canFinish(numTasks, prerequisites){
let graph = make_graph(numTasks, prerequisites);
let onpath = new Array(numTasks).fill( false );
let visited = new Array(numTasks).fill( false );
for (let i = 0; i < numTasks; i++){
if (visited[i] == false && dfs_cycle(graph, i, onpath, visited ) == true ){
return false ;
}
}
return true ;
}
let numTasks = 4;
let prerequisites = [];
prerequisites.push([1, 0]);
prerequisites.push([2, 1]);
prerequisites.push([3, 2]);
if (canFinish(numTasks, prerequisites))
console.log( "Possible to finish all tasks" );
else
console.log( "Impossible to finish all tasks" );
|
OutputPossible to finish all tasks
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)
Using BFS:
BFS can be used to solve it using the idea of topological sort. If topological sorting is possible, it means there is no cycle and it is possible to finish all the tasks.
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. If we have not returned false, we will return true.
Implementation:
C++
#include <bits/stdc++.h>
using namespace std;
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;
}
vector< 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;
}
bool canFinish( int numTasks,
vector<pair< int , int > >& prerequisites)
{
vector<unordered_set< int > > graph
= make_graph(numTasks, prerequisites);
vector< int > degrees = compute_indegree(graph);
for ( int i = 0; i < numTasks; i++) {
int j = 0;
for (; j < numTasks; j++)
if (!degrees[j])
break ;
if (j == numTasks)
return false ;
degrees[j] = -1;
for ( int neigh : graph[j])
degrees[neigh]--;
}
return true ;
}
int main()
{
int numTasks = 4;
vector<pair< int , int > > prerequisites;
prerequisites.push_back(make_pair(1, 0));
prerequisites.push_back(make_pair(2, 1));
prerequisites.push_back(make_pair(3, 2));
if (canFinish(numTasks, prerequisites)) {
cout << "Possible to finish all tasks" ;
}
else {
cout << "Impossible to finish all tasks" ;
}
return 0;
}
|
Java
import java.util.*;
public class GFG {
static class pair {
int first, second;
pair( int first, int second)
{
this .first = first;
this .second = second;
}
}
static ArrayList<ArrayList<Integer> >
make_graph( int numTasks, Vector<pair> prerequisites)
{
ArrayList<ArrayList<Integer> > graph
= new ArrayList<ArrayList<Integer> >(numTasks);
for ( int i = 0 ; i < numTasks; i++) {
graph.add( new ArrayList<Integer>());
}
for (pair pre : prerequisites)
graph.get(pre.second).add(pre.first);
return graph;
}
static int [] compute_indegree(
ArrayList<ArrayList<Integer> > graph)
{
int degrees[] = new int [graph.size()];
for (ArrayList<Integer> neighbors : graph)
for ( int neigh : neighbors)
degrees[neigh]++;
return degrees;
}
static boolean canFinish( int numTasks,
Vector<pair> prerequisites)
{
ArrayList<ArrayList<Integer> > graph
= make_graph(numTasks, prerequisites);
int degrees[] = compute_indegree(graph);
for ( int i = 0 ; i < numTasks; i++) {
int j = 0 ;
for (; j < numTasks; j++)
if (degrees[j] == 0 )
break ;
if (j == numTasks)
return false ;
degrees[j] = - 1 ;
for ( int neigh : graph.get(j))
degrees[neigh]--;
}
return true ;
}
public static void main(String args[])
{
int numTasks = 4 ;
Vector<pair> prerequisites = new Vector<pair>();
prerequisites.add( new pair( 1 , 0 ));
prerequisites.add( new pair( 2 , 1 ));
prerequisites.add( new pair( 3 , 2 ));
if (canFinish(numTasks, prerequisites)) {
System.out.println(
"Possible to finish all tasks" );
}
else {
System.out.println(
"Impossible to finish all tasks" );
}
}
}
|
Python3
class pair:
def __init__( self , first, second):
self .first = first
self .second = second
def make_graph(numTasks, prerequisites):
graph = []
for i in range (numTasks):
graph.append([])
for pre in prerequisites:
graph[pre.second].append(pre.first)
return graph
def compute_indegree(graph):
degrees = [ 0 ] * len (graph)
for neighbors in graph:
for neigh in neighbors:
degrees[neigh] + = 1
return degrees
def canFinish(numTasks, prerequisites):
graph = make_graph(numTasks, prerequisites)
degrees = compute_indegree(graph)
for i in range (numTasks):
j = 0
while (j < numTasks):
if (degrees[j] = = 0 ):
break
j + = 1
if (j = = numTasks):
return False
degrees[j] = - 1
for neigh in graph[j]:
degrees[neigh] - = 1
return True
numTasks = 4
prerequisites = []
prerequisites.append(pair( 1 , 0 ))
prerequisites.append(pair( 2 , 1 ))
prerequisites.append(pair( 3 , 2 ))
if (canFinish(numTasks, prerequisites)):
print ( "Possible to finish all tasks" )
else :
print ( "Impossible to finish all tasks" )
|
C#
using System;
using System.Collections.Generic;
public class GFG {
public class pair {
public int first, second;
public pair( int first, int second)
{
this .first = first;
this .second = second;
}
}
static List<List< int > >
make_graph( int numTasks, List<pair> prerequisites)
{
List<List< int > > graph
= new List<List< int > >(numTasks);
for ( int i = 0; i < numTasks; i++) {
graph.Add( new List< int >());
}
foreach (pair pre in prerequisites)
graph[pre.second].Add(pre.first);
return graph;
}
static int [] compute_indegree(
List<List< int > > graph)
{
int [] degrees = new int [graph.Count];
foreach (List< int > neighbors in graph)
foreach ( int neigh in neighbors)
degrees[neigh]++;
return degrees;
}
static bool canFinish( int numTasks,
List<pair> prerequisites)
{
List<List< int > > graph
= make_graph(numTasks, prerequisites);
int [] degrees = compute_indegree(graph);
for ( int i = 0; i < numTasks; i++) {
int j = 0;
for (; j < numTasks; j++)
if (degrees[j] == 0)
break ;
if (j == numTasks)
return false ;
degrees[j] = -1;
foreach ( int neigh in graph[j])
degrees[neigh]--;
}
return true ;
}
public static void Main(String[] args)
{
int numTasks = 4;
List<pair> prerequisites = new List<pair>();
prerequisites.Add( new pair(1, 0));
prerequisites.Add( new pair(2, 1));
prerequisites.Add( new pair(3, 2));
if (canFinish(numTasks, prerequisites)) {
Console.WriteLine(
"Possible to finish all tasks" );
}
else {
Console.WriteLine(
"Impossible to finish all tasks" );
}
}
}
|
Javascript
<script>
class Node {
constructor(){
this .value = 0;
this .next = null ;
}
}
let head = null ;
let one = null ;
let two = null ;
let three = null ;
one = new Node();
two = new Node();
three = new Node();
one.value = 1;
two.value = 2;
three.value = 3;
one.next = two;
two.next = three;
three.next = null ;
head = one;
while (head != null ) {
document.write(head.value);
head = head.next;
}
</script>
|
OutputPossible to finish all tasks
Time Complexity: O(V+E), where V is the number of vertices and E is the number of edges.
Auxiliary Space: O(V+E)