CourseSchedule
- 问题描述:输入一个n代表我们有N门课程,编码成0-n-1, 然后给一系列课程的前置条件,问这样安排课程是否合理。
- 问题可以转化成判断图中是否有环的问题。
- 我们将每门课程看成一个节点。
- 前置条件是条有向的边。
- 所有图是有向图。
- 如果图中存在环则前置课程必定存在冲突,否则则不冲突。
- 是否存在环?
- 解法1
- 我们首先计算每个节点的入度。
- 将所有入度为0的节点加入队列中
- 依次遍历队列中的节点, 队列为空则退出
- 针对每个节点,我们删除其所有边,并且对应节点的入度减1。
- 如果最后所有节点都遍历了,则没有环,否则有环
- 解法2
- 我们利用dfs来遍历。
- 我们针对每个点有三个状态0,1,2
- 0 代表这个点还没访问
- 1 代表正在访问,当前连通分量还没有访问结束,如果碰到将要访问的点是1,则代表有环
- 2 代表该点已经访问过,且该点所在的连通分量也访问完成。
#include <vector>
#include <iostream>
using namespace std;
class Solution {
public:
bool canFinishBase(int** graph, int n, int cur, int* visit, int* father){
visit[cur] = 1;
for(int i=0;i<n;i++){
if(i!=cur && graph[cur][i] == 1){
if(visit[i] == 1 && father[i] != cur){
return true;
}else{
if(visit[i] == 0){
father[i] = cur;
if(canFinishBase(graph, n, i, visit, father))
return true;
}
}
}
}
visit[cur] = 2;
return false;
}
bool canFinishV2(int numCourses, vector<vector<int>>& prerequisites){
int** graph = new int*[numCourses];
for(int i=0;i<numCourses;i++){
graph[i] = new int[numCourses];
}
int n = numCourses;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
graph[i][j] = 0;
}
}
for(auto v: prerequisites){
graph[v[0]][v[1]] = 1;
}
int* father = new int[n];
int* visit = new int[n];
for(int i=0;i<n;i++){
father[i] = -1;
visit[i] = 0;
}
for(int i=0;i<n;i++)
if(visit[i] == 0)
if(canFinishBase(graph, n, i, visit, father)){
return false;
}
return true;
}
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
int graph[numCourses][numCourses];
memset(graph, 0, sizeof(graph));
vector<int> rudu(numCourses);
for(auto v: prerequisites){
graph[v[0]][v[1]] = 1;
rudu[v[1]] += 1;
}
int n = numCourses;
vector<int> nodes;
int count = 0;
for(int i=0;i<numCourses;i++){
if(rudu[i] == 0){
nodes.push_back(i);
count += 1;
}
}
while(!nodes.empty()){
int cur_node = nodes.back();
nodes.pop_back();
for(int i=0;i<numCourses;i++){
if(graph[cur_node][i] == 1){
graph[cur_node][i] = 0;
rudu[i] -= 1;
if(rudu[i] == 0){
nodes.push_back(i);
count += 1;
}
}
}
}
return count == numCourses;
}
};