There are a total of n courses you have to take, labeled from 0
to n
- 1
.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?
For example:
2, [[1,0]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.
2, [[1,0],[0,1]]
There are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.
This is actually to detect whether the graph has cycle in directed graph.
Solution 1 : union-find.
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <iostream>
using namespace std;
int root(int a, vector<int>& dp) {
while(a != dp[a]) {
a = dp[a];
}
return a;
}
bool find(int a, int b, vector<int>& dp) {
if(dp[a] == dp[b]) return true;
else return false;
}
void unite(int a, int b, vector<int>& dp) {
int root_a = root(a, dp);
int root_b = root(b, dp);
dp[root_a] = root_b;
}
bool canFinish(int numCourses, vector< pair<int, int> >& prerequisites) {
// MakeSet.
vector<int> dp;
for(int i = 0; i < numCourses; ++i) {
dp.push_back(i);
}
vector< vector<int> > schedules(numCourses);
for(int i = 0; i < prerequisites.size(); ++i) {
auto tmp = prerequisites[i];
schedules[tmp.first].push_back(tmp.second);
}
for(int i = 0; i < schedules.size(); ++i) {
for(int j = 0; j < schedules[i].size(); ++j) {
if(find(i, schedules[i][j], dp)) return false;
else unite(i, schedules[i][j], dp);
}
}
return true;
}
int main(void) {
vector<pair<int, int> > courses{{0,1}};
vector<pair<int, int> > courses_1{{0,1}, {1, 0}};
cout << "first test : " << canFinish(2, courses) << endl;
cout << "second test : " << canFinish(2, courses_1) << endl;
}
DFS method:
bool dfsLoopDetection(const vector<vector<int> >& graph, vector<bool>& visited, int node, unordered_set<int>& startNodes) {
visited[node] = true;
for(int neighbor : graph[node]) {
if(visited[neighbor]) return true;
if(dfsLoopDetection(graph, visited, neighbor, startNodes)) return true;
}
visited[node] = false;
startNodes.erase(node);
return false;
}
bool canFinish(int numCourses, vector<pair<int, int> >& prerequisites) {
if(numCourses == 0) return true;
vector< vector<int> > graph(numCourses);
for(auto p : prerequisites) {
graph[p.first].push_back(p.second);
}
vector<bool> visited(numCourses, false);
unordered_set<int> startNodes;
for(int i = 0; i < numCourses; ++i) startNodes.insert(i);
while(!startNodes.empty()) {
int node = *(startNodes.begin());
if(dfsLoopDetection(graph, visited, node, startNodes)) return false;
}
return true;
}
int main(void) {
vector<pair<int, int> > courses {{0, 1}};
cout << canFinish(2, courses) << endl;
}