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;
}
};