验证课程安排图是否是有向无环图(DAG)。通过拓扑排序判断此课程安排图是否是有向无环图。
方法一:BFS
BFS用到的主要数据结构就是队列,如果存在环那么一定有节点的入度始终不为0.
具体原理和图解可以参考课程表(拓扑排序:入度表BFS法 / DFS法,清晰图解),这里给出ACM模式下C++的代码实现:
#include<queue>
#include<vector>
#include<list>
#include<iostream>
using namespace std;
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<int> indegree(numCourses, 0); //入度表
vector<vector<int>> adj(numCourses, vector<int>()); //后驱结点
queue<int> preq; //队列
for (auto t : prerequisites) {
indegree[t[0]]++;
adj[t[1]].push_back(t[0]);
}
for (int i = 0; i < numCourses; i++) {
if (indegree[i] == 0) preq.push(i);
}
while (!preq.empty()) {
int pre = preq.front();
numCourses--;
preq.pop();
for (int cur : adj[pre]) {
if (--indegree[cur] == 0) {
preq.push(cur);
}
}
}
return numCourses == 0;
}
};
int main() {
int num;
cin >> num;
int prev, last;
vector<vector<int>> prereq;
while (cin >> last >> prev) {
//输入EOF表示输入结束,将跳出while循环
vector<int> tmp;
tmp.push_back(last);
tmp.push_back(prev);
prereq.push_back(tmp);
}
Solution st;
cout << st.canFinish(num, prereq);
return 0;
}
方法二:DFS
DFS用到的主要数据结构为栈,在一般实现当中,会直接利用递归写代码,因为程序中的递归实际上也是栈的一种表现形式。
终止条件:
当 flag[i] == -1,说明当前访问节点已被其他节点启动的 DFS 访问,无需再重复搜索,直接返回 True。
当 flag[i] == 1,说明在本轮 DFS 搜索中节点 i 被第 2 次访问,即 课程安排图有环 ,直接返回 False。
未被 DFS 访问:i == 0
/* DFS */
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int>> adj(numCourses, vector<int>()); //后驱结点
vector<int> flags(numCourses, 0);
for (auto t : prerequisites) {
adj[t[1]].push_back(t[0]);
}
for (int i = 0; i < numCourses; i++) {
if (!dfs(adj, flags, i)) return false;
}
return true;
}
private:
bool dfs(vector<vector<int>>& adj, vector<int>& flags, int i) {
if (flags[i] == 1) return false;
if (flags[i] == -1) return true;
flags[i] = 1;
for (int j : adj[i]) {
if (!dfs(adj, flags, j))return false;
}
flags[i] = -1;
return true;
}
};
int main() {
int num;
cin >> num;
int prev, last;
vector<vector<int>> prereq;
while (cin >> last >> prev) {
//输入EOF表示输入结束,将跳出while循环
vector<int> tmp;
tmp.push_back(last);
tmp.push_back(prev);
prereq.push_back(tmp);
}
Solution st;
cout << st.canFinish(num, prereq);
return 0;
}
输出选课顺序
210.课程表 II
需要输出选课顺序,只需要在返回时插入返回结果数组的头部即可。
DFS的代码实现如下:
#include<vector>
#include<iostream>
using namespace std;
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
vector<int> flags(numCourses, 0);
vector<vector<int>> adj(numCourses,vector<int>());
vector<int> res(numCourses);
res.clear();
for (auto tmp : prerequisites) {
adj[tmp[1]].push_back(tmp[0]);
}
for (int i = 0; i < numCourses; i++) {
if (!dfs(adj, flags, i, res)) return vector<int>();
}
return res;
}
private:
bool dfs(vector<vector<int>>& adj, vector<int>& flags, int i, vector<int>& res) {
if (flags[i] == 1) return false;
if (flags[i] == -1) return true;
flags[i] = 1;
for (int j : adj[i]) {
if (!dfs(adj, flags, j, res)) return false;
}
flags[i] = -1;
res.emplace(res.begin(), i);
return true;
}
};
int main() {
int num;
cin >> num;
int prev, last;
vector<vector<int>> prereq;
while (cin >> last >> prev) {
//输入EOF表示输入结束,将跳出while循环
vector<int> tmp;
tmp.push_back(last);
tmp.push_back(prev);
prereq.push_back(tmp);
}
Solution st;
vector<int> res = st.findOrder(num, prereq);
for (auto tp : res) {
cout << tp << '\t';
}
return 0;
}