This is standard topological sort
1: First solution, using stack.
#include <vector>
#include <stack>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
/*
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 the correct course order is [0, 1]
Another example:
4, [[1, 0], [2, 0], [3, 1], [3, 2]]
There are a total of 4 courses to take. To take course 3 you should have finished both courses
1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct
course order is [0, 1, 2, 3]
Another correct ordering is [0, 2, 1, 3].
Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices.
*/
// This is clearly to do toplogical sort.
void toplogicalSort(unordered_map<int, vector<int> > courses, unordered_map<int, bool>& visited, stack<int>& nodes, int i) {
visited[i] = true;
vector<int> edges = courses[i];
for(int k = 0; k < edges.size(); ++k) {
if(!visited[edges[k]]) {
toplogicalSort(courses, visited, nodes, edges[k]);
}
} nodes.push(i); // notice this line. After traversing all the nodes, push it backward.
}
vector<int> findOrder(int numCourses, vector<pair<int, int> >& prerequisites) {
unordered_map<int, bool> visited;
for(int i = 0; i < numCourses; ++i) {
visited[i] = false;
}
unordered_map<int, vector<int> > courses;
for(int i = 0; i < prerequisites.size(); ++i) {
int first = prerequisites[i].first;
int second = prerequisites[i].second;
courses[first].push_back(second);
}
stack<int> nodes;
for(int i = 0; i < numCourses; ++i) {
if(!visited[i]) {
toplogicalSort(courses, visited, nodes, i);
}
}
vector<int> res;
while(!nodes.empty()) {
int tmp = nodes.top();
nodes.pop();
res.push_back(tmp);
}
return res;
}
int main(void) {
vector< pair<int, int> > prerequisites{{1, 0}, {2, 0}, {3, 1}, {3, 2}};
vector<int> res = findOrder(4, prerequisites);
reverse(res.begin(), res.end());
for(int i = 0; i < res.size(); ++i) {
cout << res[i] << " ";
}
cout << endl;
}
2: Second solution.
First find the degree 0 vertex and apply dfs search.
class Solution {
public:
vector<int> findOrder(int numCourses, vector<pair<int, int>>& prerequisites) {
if (numCourses == 0) return vector<int>(0, 0);
unordered_map<int, vector<int> > adjacentList;
vector<int> startList(numCourses, 0);
for (auto pre : prerequisites) {
adjacentList[pre.first].push_back(pre.second);
startList[pre.second]++; // this is the graph node's degree.
}
int visitedNodes = 0;
vector<int> marks(numCourses, 0); // 0 indicates not marked, 1 temporary marked, 2 permanent marked
vector<int> orders;
while (visitedNodes < numCourses) {
//find one unvisited node with indegree == 0
int startNode = findOneUnvisitedNode(numCourses, startList, marks);
// if cannot find a startNode, return false;
if (startNode >= numCourses) return vector<int>(0, 0);
// dfs from start node
if (!dfs(startNode, adjacentList, marks, visitedNodes, orders)) return vector<int>(0, 0);
}
return orders;
}
int findOneUnvisitedNode(int numCourses, vector<int>& startList, vector<int>& marks) {
int startNode = 0;
for (; startNode < numCourses; startNode++) {
if (startList[startNode] == 0 && marks[startNode] == 0)
break;
}
return startNode;
}
bool dfs (int startNode, unordered_map<int, vector<int> >& adjacentList, vector<int>& marks, int & visitedNodes, vector<int>& orders) {
if (marks[startNode] == 1) return false;
if (marks[startNode] == 0) {
marks[startNode] = 1;
//visit all adjacent node
for (auto neighbor : adjacentList[startNode]) {
if (!dfs(neighbor, adjacentList, marks, visitedNodes, orders)) return false;
}
marks[startNode] = 2;
orders.push_back(startNode);
visitedNodes++;
}
return true;
}
};
https://leetcode.com/discuss/90109/dfs-c-solution-topological-sort
https://courses.cs.washington.edu/courses/cse326/03wi/lectures/RaoLect20.pdf