題目地址:Course Schedule
題目簡介:
現在你總共有 n 門課需要選,記爲 0 到 n-1。但是在選修某些課程之前需要一些先修課程, 例如,想要學習高等數學,你需要先學完高中數學。
我們用一個匹配來表示他們: [0,1]給定課程總量以及它們的先決條件,判斷是否可能完成所有課程的學習?
Example 1:
Input: 2, [[1,0]]
Output: true
Explanation: 總共有 2 門課程,學習課程 1 之前,你需要完成課程 0,所以這是可能的。
Example 2:
Input: 2, [[1,0],[0,1]]
Output: false
Explanation: 總共有 2 門課程,學習課程 1 之前,你需要先完成課程 0;並且學習課程 0 之前,你還應先完成課程 1,這是不可能的。
說明:輸入的先決條件是由邊緣列表表示的圖形,而不是鄰接矩陣,詳情請參見圖的表示法。
可以假定輸入的先決條件中沒有重複的邊。
提示:這個問題相當於查找一個循環是否存在於有向圖中。如果存在循環,則不存在拓撲排序,因此不可能選取所有課程進行學習。
題目解析:
1、有向無環圖
數據結構中的有向無環圖,即所有點之間的關聯都是單向的,並且不會出現環。拓撲排序是將G中所有頂點排成一個線性序列,使得圖中任意一對頂點u(先決課)和v(後上課),若邊(u,v)∈E(G),則u在線性序列中出現在v之前。
整體的步驟如下:
(1) 選擇一個入度爲0的頂點並輸出之;
(2) 從網中刪除此頂點及所有出邊。
循環結束後,若輸出的頂點數小於網中的頂點數,則輸出“有迴路”信息,否則輸出的頂點序列就是一種拓撲序列。
C++版:
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<vector<int> > relation(numCourses, vector<int>(0));
vector<int> waiting(numCourses, 0);
for (auto cur : prerequisites)
{
relation[cur[1]].push_back(cur[0]);
waiting[cur[0]]++;
}
queue<int> done; //存放當前可以上的課程
for (int i = 0; i < numCourses; ++i)
{
if (waiting[i] == 0)
done.push(i);
}
while (!done.empty())
{
int finished = done.front();
done.pop();
for (auto a : relation[finished])
{
waiting[a]--;
if (waiting[a] == 0)
done.push(a);
}
}
for (int i = 0; i < numCourses; ++i)
{
if (waiting[i] != 0)
return false;
}
return true;
}
};
Python代碼參考:Python3 BFS faster than 96.75%
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
relation = collections.defaultdict(list)
waiting = [0 for i in range(numCourses)]
for cur in prerequisites:
relation[cur[1]].append(cur[0])
waiting[cur[0]] += 1
queue = []
for i in relation:
if waiting[i] == 0:
queue.append(i)
while queue!=[]:
done = queue.pop()
for sche in relation[done]:
waiting[sche] -= 1
if waiting[sche] == 0:
queue.append(sche)
for t in waiting:
if waiting[t]!=0:
return False
return True