1. 程式人生 > 其它 >207. 課程表(拓撲排序bfs)

207. 課程表(拓撲排序bfs)

 

你這個學期必須選修 numCourses 門課程,記為 0 到 numCourses - 1 。

在選修某些課程之前需要一些先修課程。 先修課程按陣列 prerequisites 給出,其中 prerequisites[i] = [ai, bi] ,表示如果要學習課程 ai 則 必須 先學習課程  bi 。

  • 例如,先修課程對 [0, 1] 表示:想要學習課程 0 ,你需要先完成課程 1 。

請你判斷是否可能完成所有課程的學習?如果可以,返回 true ;否則,返回 false 。

示例 1:

輸入:numCourses = 2, prerequisites = [[1,0]]
輸出:true
解釋:總共有 2 門課程。學習課程 1 之前,你需要完成課程 0 。這是可能的。

示例 2:

輸入:numCourses = 2, prerequisites = [[1,0],[0,1]]
輸出:false
解釋:總共有 2 門課程。學習課程 1 之前,你需要先完成​課程 0 ;並且學習課程 0 之前,你還應先完成課程 1 。這是不可能的。
   

題意解釋
一共有 n 門課要上,編號為 0 ~ n-1。
先決條件[1, 0],意思是必須先上課 0,才能上課 1。
給你 n 、和一個先決條件表,請你判斷能否完成所有課程。
再舉個生活的例子
先穿內褲再穿褲子,先穿打底再穿外套,先穿衣服再戴帽子,是約定俗成的。
內褲外穿、光著身子戴帽子等,都會有點奇怪。
我們遵循穿衣的一條條先後規則,用一串順序行為,把衣服一件件穿上。
我們遵循課程之間的先後規則,找到一種上課順序,把所有課一節節上完。
用有向圖描述依賴關係
示例:n = 6,先決條件表:[[3, 0], [3, 1], [4, 1], [4, 2], [5, 3], [5, 4]]
課 0, 1, 2 沒有先修課,可以直接選。其餘的課,都有兩門先修課。
我們用有向圖來展現這種依賴關係(做事情的先後關係):

這種叫 有向無環圖,把一個 有向無環圖 轉成 線性的排序 就叫 拓撲排序。
有向圖有 入度 和 出度 的概念:
如果存在一條有向邊 A --> B,則這條邊給 A 增加了 1 個出度,給 B 增加了 1 個入度。
所以,頂點 0、1、2 的入度為 0。頂點 3、4、5 的入度為 2。
每次只能選你能上的課
每次只能選入度為 0 的課,因為它不依賴別的課,是當下你能上的課。
假設選了 0,課 3 的先修課少了一門,入度由 2 變 1。
接著選 1,導致課 3 的入度變 0,課 4 的入度由 2 變 1。
接著選 2,導致課 4 的入度變 0。
現在,課 3 和課 4 的入度為 0。繼續選入度為 0 的課……直到選不到入度為 0 的課。
這很像 BFS
讓入度為 0 的課入列,它們是能直接選的課。
然後逐個出列,出列代表著課被選,需要減小相關課的入度。
如果相關課的入度新變為 0,安排它入列、再出列……直到沒有入度為 0 的課可入列。
BFS 前的準備工作
每門課的入度需要被記錄,我們關心入度值的變化。
課程之間的依賴關係也要被記錄,我們關心選當前課會減小哪些課的入度。
因此我們需要選擇合適的資料結構,去存這些資料:
入度陣列:課號 0 到 n - 1 作為索引,通過遍歷先決條件表求出對應的初始入度。
鄰接表:用雜湊表記錄依賴關係(也可以用二維矩陣,但有點大)
key:課號
value:依賴這門課的後續課(陣列)
怎麼判斷能否修完所有課?
BFS 結束時,如果仍有課的入度不為 0,無法被選,完成不了所有課。否則,能找到一種順序把所有課上完。
或者:用一個變數 count 記錄入列的頂點個數,最後判斷 count 是否等於總課程數。

作者:xiao_ben_zhu
連結:https://leetcode.cn/problems/course-schedule/solution/bao-mu-shi-ti-jie-shou-ba-shou-da-tong-tuo-bu-pai-/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

     
 1 class Solution {
 2 public:
 3     bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
 4 
 5         unordered_map<int,std::vector<int>> map;
 6         vector<int> ingreed(numCourses,0);
 7         for(int i = 0; i < prerequisites.size();i++) {
 8             ingreed[prerequisites[i][0]]++;
 9             map[prerequisites[i][1]].emplace_back(prerequisites[i][0]);
10         }
11         queue<int> q;
12         for(int i = 0; i < ingreed.size();i++) {
13             if (ingreed[i]==0) {
14                 q.push(i);
15             }
16         }
17         int cnt = 0;
18         while(!q.empty()) {
19             int top = q.front();
20             q.pop();
21             cnt++;
22             for(auto adj: map[top]) {
23                 ingreed[adj]--;
24                 if (ingreed[adj]==0) {
25                     q.push(adj);
26                 }
27             }
28         }
29         return cnt == numCourses;
30     }
31 };