I have solved this problem as a solution for this Leetcode problem - https://leetcode.com/problems/course-schedule/
I have implemented it in Java - using recursive DFS using colors, recursive DFS using visited array, iterative DFS and BFS using indegree and calculating topological sort.
class Solution {
//prereq is the edges and numCourses is number of vertices
public boolean canFinish(int numCourses, int[][] prereq) {
//0 -> White, -1 -> Gray, 1 -> Black
int [] colors = new int[numCourses];
boolean [] v = new boolean[numCourses];
int [] inDegree = new int[numCourses];
Map<Integer, List<Integer>> alMap = new HashMap<>();
for(int i = 0; i < prereq.length; i++){
int s = prereq[i][0];
int d = prereq[i][1];
alMap.putIfAbsent(s, new ArrayList<>());
alMap.get(s).add(d);
inDegree[d]++;
}
// if(hasCycleBFS(alMap, numCourses, inDegree)){
// return false;
// }
for(int i = 0; i < numCourses; i++){
if(hasCycleDFS1(i, alMap, colors)){
// if(hasCycleDFS2(i, alMap, v)){
//if(hasCycleDFSIterative(i, alMap, colors)){
return false;
}
}
return true;
}
//12.48
boolean hasCycleBFS(Map<Integer, List<Integer>> alMap, int numCourses, int [] inDegree){
//short [] v = new short[numCourses];
Deque<Integer> q = new ArrayDeque<>();
for(int i = 0; i < numCourses; i++){
if(inDegree[i] == 0){
q.offer(i);
}
}
List<Integer> tSortList = new ArrayList<>();
while(!q.isEmpty()){
int cur = q.poll();
tSortList.add(cur);
//System.out.println("cur = " + cur);
if(alMap.containsKey(cur)){
for(Integer d: alMap.get(cur)){
//System.out.println("d = " + d);
// if(v[d] == true){
// return true;
// }
inDegree[d]--;
if(inDegree[d] == 0){
q.offer(d);
}
}
}
}
return tSortList.size() == numCourses? false: true;
}
// inspired from - https://leetcode.com/problems/course-schedule/discuss/58730/Explained-Java-12ms-Iterative-DFS-solution-based-on-DFS-algorithm-in-CLRS
//0 -> White, -1 -> Gray, 1 -> Black
boolean hasCycleDFSIterative(int s, Map<Integer, List<Integer>> alMap, int [] colors){
Deque<Integer> stack = new ArrayDeque<>();
stack.push(s);
while(!stack.isEmpty()){
int cur = stack.peek();
if(colors[cur] == 0){
colors[cur] = -1;
if(alMap.containsKey(cur)){
for(Integer d: alMap.get(cur)){
if(colors[d] == -1){
return true;
}
if(colors[d] == 0){
stack.push(d);
}
}
}
}else if (colors[cur] == -1 || colors[cur] == 1){
colors[cur] = 1;
stack.pop();
}
}
return false;
}
boolean hasCycleDFS1(int s, Map<Integer, List<Integer>> alMap, int [] colors){
// if(v[s] == true){
// return true;
// }
colors[s] = -1;
if(alMap.containsKey(s)){
for(Integer d: alMap.get(s)){
//grey vertex
if(colors[d] == -1){
return true;
}
if(colors[d] == 0 && hasCycleDFS1(d, alMap, colors)){
return true;
}
}
}
colors[s] = 1;
return false;
}
// not efficient because we process black vertices again
boolean hasCycleDFS2(int s, Map<Integer, List<Integer>> alMap, boolean [] v){
// if(v[s] == true){
// return true;
// }
v[s] = true;
if(alMap.containsKey(s)){
for(Integer d: alMap.get(s)){
if(v[d] == true || hasCycleDFS2(d, alMap, v)){
return true;
}
}
}
v[s] = false;
return false;
}
}