###### tags: `Leetcode` `medium` `graph` `topological sort` `dfs` `bfs` `python` `c++` `Top 100 Liked Questions`
# 207. Course Schedule
There are a total of ```numCourses``` courses you have to take, labeled from ```0``` to ```numCourses - 1```. You are given an array ```prerequisites``` where ```prerequisites[i] = [ai, bi]``` indicates that you **must** take course ```bi``` first if you want to take course ```ai```.
* For example, the pair ```[0, 1]```, indicates that to take course ```0``` you have to first take course ```1```.
Return **true** if you can finish all courses. Otherwise, return **false**.

## 解題想法:
* 同類型題目: [210. Course Schedule II](/p2vAVMAwRdyn_Wb9O7UZpA)
* 題目為,有幾堂課,並且有修課的先後順序,是否能修完所有課
* numCourses課數
* prerequisites[i] = [ai, bi]
* 必須先修完修bi才能修ai
* 本質為在**有向圖中檢查是否有環**
### **法1: 拓樸排序BFS**
* time: O(n^2) space:O(n)
* Step1: 建立有向邊
* ex:[0,1],表示: 1->0
```python=
for v,u in prerequisites:
graph[u].append(v) #u指向v
indegrees[v]+=1 #有人指向v 所以v的indegrees+1
```
* Step2: 存所有indegree為0的點
```python=
zeroIndegree = [i for i in range(numCourses) if indegrees[i]==0]
#不能用 " i for i in indegrees "
#Wrong: zeroIndegree = [i for i in indegrees if indegrees[i]==0]
#因為雖然用defaultdict(int)
#但是step1建立邊時,indegree只針對非0者進行壘加,所以不知道哪些node indegree為0
```
* Step3: while每次選擇indegree為0的點,刪掉該點連的所有邊
* 直到找不到-> 存在環
* 若剛好操作n次(n為節點數) -> 無環圖DAG(Directed Acyclic Graph)
```python=
visited = 0 #已經拜訪過的點數量
#BFS
while zeroIndegree:
cur = zeroIndegree.pop()
visited+=1
#遍歷所有被cur連到的點
for node in graph[cur]:
#將其indegrees-1
indegrees[node]-=1
if indegrees[node]==0:
zeroIndegree.append(node)
```
## Python: BFS
``` python=
from collections import defaultdict
class Solution(object):
def canFinish(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: bool
"""
#graph topological
graph=defaultdict(list)
indegrees=defaultdict(int) #key的默認val為0
#建立圖
for v,u in prerequisites:
#ex: 給[0,1] 表示 1->0
graph[u].append(v)
indegrees[v]+=1
#存indegrees=0的點
zeroIndegree = [i for i in range(numCourses) if indegrees[i]==0]
visited = 0 #已經拜訪過的點
#BFS:
while zeroIndegree:
cur = zeroIndegree.pop()
visited+=1
#遍歷所有被cur連到的點
for node in graph[cur]:
#將其in-1
indegrees[node]-=1
if indegrees[node]==0:
zeroIndegree.append(node)
return True if visited==numCourses else False
if __name__=='__main__':
numCourses = 2
prerequisites = [[1,0]]
result=Solution()
ans = result.canFinish(numCourses,prerequisites)
print(ans)
```
## C++: BFS
``` cpp=
#include<bits/stdc++.h>
using namespace std;
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
unordered_map<int, vector<int>> graph;
unordered_map<int, int> indegree;
for (int i=0; i<numCourses; i++){
indegree[i]=0;
}
//connect the graph
for (auto course: prerequisites){
graph[course[1]].push_back(course[0]);
indegree[course[0]]+=1;
}
stack<int> zeroIndegrees;
//unorder_map: first,second
//key: course.first
//val: course.second
for (auto& course: indegree){ //pointer need &
if (course.second==0)
zeroIndegrees.push(course.first);
}
int visited=0;
//bfs
int curNode;
while (!zeroIndegrees.empty()){
curNode=zeroIndegrees.top(); zeroIndegrees.pop();
visited+=1;
for (auto neiber: graph[curNode]){
indegree[neiber]-=1;
if (indegree[neiber]==0)
zeroIndegrees.push(neiber);
}
}
return (visited==numCourses)? true:false;
}
};
int main(){
Solution res;
int numCourse=2;
vector<vector<int>> prerequsites={
{1,0},
{0,1}
};
bool ans=res.canFinish(numCourse,prerequsites);
cout<<ans<<endl; //0 false
return 0;
}
```
### 法2: 拓樸排序DFS
* time、space: **皆O(n)**
* Step1: 建立有向邊
* ex:[0,1],表示: 1->0
```python=
graph = defaultdict(list)
for v,u in prerequisites:
graph[u].append(v)
```
* Step2: 對於每點,設不同狀態進行判別
* 0 = Unknown
* 1 = visiting
* 2 = visited
``` python=
# 0 = Unknown, 1 = visiting, 2 = visited
visit = [0]*numCourses
```
* Step3: 每次找到新點,判斷此點出發是否有環
``` python=
for i in range(numCourses):
if self.checkDAG(graph,visit,i)==False:
return False
return True
```
* Step4: 子程式bool checkDAG()判斷當前點的拜訪狀態:
``` python=
def checkDAG(self,graph,visit,i):
if visit[i]==1: #有cycle
return False
elif visit[i]==2: #安全
return True
else: #初次拜訪
visit[i]=1 #將自己狀態改為拜訪中
#遍歷鄰居
for node in graph[i]:
if self.checkDAG(graph,visit,node)==False:
return False
visit[i]=2 #將自己狀態改為已遍歷
return True
```
## Python: DFS
```python=
from collections import defaultdict
class Solution(object):
def canFinish(self, numCourses, prerequisites):
"""
:type numCourses: int
:type prerequisites: List[List[int]]
:rtype: bool
"""
#graph topological
#dfs time space: 皆O(N)
graph = defaultdict(list)
for v,u in prerequisites:
graph[u].append(v)
# 0 = Unknown, 1 = visiting, 2 = visited
visit = [0]*numCourses
for i in range(numCourses):
if self.checkDAG(graph,visit,i)==False:
return False
return True
def checkDAG(self,graph,visit,i):
if visit[i]==1: #有cycle
return False
elif visit[i]==2: #安全
return True
else: #初次拜訪
visit[i]=1
#遍歷鄰居
for node in graph[i]:
if self.checkDAG(graph,visit,node)==False:
return False
visit[i]=2
return True
if __name__=='__main__':
numCourses = 2
prerequisites = [[1,0]]
result=Solution()
ans = result.canFinish(numCourses,prerequisites)
print(ans)
```
## C++: DFS
``` cpp=
#include<bits/stdc++.h>
using namespace std;
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
unordered_map<int, vector<int>> graph;
//connect the graph
for (auto course: prerequisites){
graph[course[1]].push_back(course[0]);
}
//init the visited list
//0: unKnown 1:visiting 2:visited
vector<int> visited(numCourses,0);
//dfs
for (int i=0; i<numCourses; i++){
if (checkDAG(graph,visited,i)==false)
return false;
}
return true;
}
bool checkDAG(unordered_map<int, vector<int>>& graph, vector<int>& visited, int curPos){
if (visited[curPos]==1)
return false;
else if (visited[curPos]==2)
return true;
else{
visited[curPos]=1;
//check neighbor of curPos in graph
for (auto neighbor: graph[curPos]){
if (checkDAG(graph,visited,neighbor)==false)
return false;
}
visited[curPos]=2;
return true;
}
}
};
int main(){
Solution res;
int numCourse=2;
vector<vector<int>> prerequsites={
{1,0},
{0,1}
};
bool ans=res.canFinish(numCourse,prerequsites);
cout<<ans<<endl; //0 false
return 0;
}
```