# LeetCode 1462. Course Schedule IV https://leetcode.com/problems/course-schedule-iv/description/ ## 題目大意 共有 `numCourses` 門課程,課程以 `0` 到 `numCourses - 1` 進行編號 你會得到一個陣列 `prerequisites`,其中 `prerequisites[i] = [ai, bi]` 表示如果你想修課程 `bi`,則必須先修過 `ai` 先修課程的條件也可以是**間接**的: 如果課程 `a` 是課程 `b` 的先修課程,且課程 `b` 是課程 `c` 的先修課程,那麼課程 `a` 也是課程 `c` 的先修課程 給定陣列 `queries`,其中 `queries[j] = [uj, vj]` 對於第 `j` 個查詢,你需要回答課程 `uj` 是否為課程 `vj` 的先修課程 回傳一個布林陣列 `answer`,其中 `answer[j]` 是第 `j` 個查詢的答案 ## 思考 這題有個關鍵句: **先修課程的條件也可以是間接的** 這提示了我們,這題其實可以看作是解[遞移閉包](https://hackmd.io/@RyoukiWei/graph_2#Transtive-Closure)的問題 怎麼說? Let the courses $C$ be represented as a set of integers $\left\{0, 1, \cdots , n-1\right\}$ Define a binary relation $R\subseteq C\times C$: $(a, b)\in R \Leftrightarrow \text{course } a \text{ is a prereqisites for course } b.$ 題目給定的 `prerequisites` 就可理解為 For each pair $\left[ a,b \right]\in\mathrm{prerequisites}$, we have $(a,b)\in R$ 何謂遞移包 ($R^+$) 呢?即 $R$ 之最小子集合滿足遞移性: $\text{If }(a,b)\in R^+ \text{and } (b,c)\in R^+, \text{then } (a, c)\in R^+$ 你會發現這正對應了題目原文所說的: > If course a is a prerequisite of course b, and course b is a prerequisite of course c, then course a is a prerequisite of course c. 所以這題我們用 Floyd-Warshall Algorithm 解 定義相鄰矩陣 $T$ : $$ T\left\lbrack i \right\rbrack \left\lbrack j \right\rbrack = \begin{cases} 1 &&\text{ if }(i,j)\in R\\ 0 &&\text{ otherwise} \end{cases} $$ 遞迴關係式為: $$ T_{ij} = T_{ij}\vee (T_{ik}\wedge T_{kj}) $$ 其中 $k$ 為 $i$ 到 $j$ 路徑上之中繼點 ### C++ 參考解答 ```cpp! class Solution { public: vector<bool> checkIfPrerequisite(int numCourses, vector<vector<int>> &prerequisites, vector<vector<int>> &queries) { vector<bool> ans; vector<vector<bool>> isPrereqisite(numCourses, vector<bool>(numCourses)); for (const auto &prereqisite : prerequisites) { const int u = prereqisite[0]; const int v = prereqisite[1]; isPrereqisite[u][v] = true; } for (int k = 0; k < numCourses; ++k) { for (int i = 0; i < numCourses; ++i) { if (!isPrereqisite[i][k]) continue; for (int j = 0; j < numCourses; ++j) { isPrereqisite[i][j] = isPrereqisite[i][j] || (isPrereqisite[i][k] && isPrereqisite[k][j]); } } } ans.reserve(queries.size()); for (const auto &query : queries) { const int u = query[0]; const int v = query[1]; ans.push_back(isPrereqisite[u][v]); } return ans; } }; ``` ### Go 參考解答 ```go! func checkIfPrerequisite(numCourses int, prerequisites [][]int, queries [][]int) []bool { isPrerequisite := make([][]bool, numCourses) for i := 0; i < numCourses; i++ { isPrerequisite[i] = make([]bool, numCourses) } for _, prereq := range prerequisites { u, v := prereq[0], prereq[1] isPrerequisite[u][v] = true } for k := 0; k < numCourses; k++ { for i := 0; i < numCourses; i++ { if !isPrerequisite[i][k] { continue } for j := 0; j < numCourses; j++ { isPrerequisite[i][j] = isPrerequisite[i][j] || isPrerequisite[i][k] && isPrerequisite[k][j] } } } ans := make([]bool, len(queries)) for i, query := range queries { u, v := query[0], query[1] ans[i] = isPrerequisite[u][v] } return ans } ```