考慮你有修課的順序如下, 箭頭說明該課程有相依性. 如 計概->計組 指 "計概" 要先修完後才能修 "計組":
而我們的問題是要找出一種修課的順序可以滿足上面拓撲圖的要求, 而這類的問題稱之為 Topology sort. 底下是 wiki 上面較詳細的說明:
上面說明的 vertex 就可以看成課程, 而 edge 說明課程間的相依性. 而這樣的 Graph 必須滿足 DAG (directed acyclic grapn) 而這類問題的圖形也稱為 AOV (activity on vertex).
Using DFS as Solution:
要解決這個問題一個常見的解法是使用 DFS (Deep First Search). 在跑 DFS 的過程中每個 vertex 都會產生所謂的 discover time 與 finish time. 而 finish time 較小的 vertex 相對 finish time 較大的 vertex 在圖形中較 deep 的位置. 底下是 DFS 的 pseudo code:
上面的 u.f 指的即是 finish time. 因此直覺的可以將 vertex 依其 finish time 以 decreasing order 排列後, 取出的的順序便是其中一個可能的解法. (finish time 較大的先取出來, 即由 root 依序往其 leaf 移動). 而其實 finish time 大的先取; 小的後取 的概念類似於 ADT Stack 的想法 (FILO - First in Last out 或是 LIFO - Last in First out), 因此下面的實作中當每個 vertex 狀態由 Gray->Black (finish), 便將之加入 stack, 最後將該 stack 返回並依序取出 vertex 便是 Topology sort 的結果.
Implementation:
下面類別 TopologicalSort 實作了使用 DFS 的 Topology sort: (完整代碼)
- package map.alg;
- import java.util.Stack;
- public class TopologicalSort {
- public static void _DFS_Visit(Stack
stack, Vertex v) - {
- v.status = EStatus.Gray;
- // Discover
- for(Edge e:v.edgeSet)
- {
- if(e.to.status.equals(EStatus.White)) _DFS_Visit(stack, e.to);
- }
- // Finish
- v.status = EStatus.Black;
- stack.add(v);
- }
- /**
- * Alg:
- * 1. Run DFS(G)
- * 2. v.f 越小說明其在 DFS 是處於較 deep 的位置 (相依性重). 因此它應該較後面處理.
- * 這邊我們使用 stack 來存放處理完畢的 vertex (依 finish 先後順序放入 stack)
- * 3. 從 Stack 取出的順序即是 Topological sort 的順序.
- *
- * Ref:
- * - Wiki Topology sort
- * http://en.wikipedia.org/wiki/Topological_sorting
- *
- * @param g
- * @return
- */
- public static Stack
Go(Graph g) - {
- // 0) Initialize
- Stack
stack = new Stack (); - for(Vertex v:g.vtxMap.values())
- {
- v.pi = null;
- v.status = EStatus.White;
- }
- // 1) Start DFS
- for (Vertex v : g.vtxMap.values()) {
- if (v.status.equals(EStatus.White)) {
- _DFS_Visit(stack, v);
- }
- }
- return stack;
- }
- }
底下是使用上面類別來解決一開始的課程問題, 輸出為其中一個可能的修課順序:
- public static void main(String args[])
- {
- // 0) Prepare Graph
- Graph g = new Graph(true); // Directed graph
- g.addVertex("微積分上"); g.addVertex("微積分下"); g.addVertex("機率");
- g.addVertex("計概"); g.addVertex("計組"); g.addVertex("作業系統");
- g.addVertex("計程"); g.addVertex("演算法上"); g.addVertex("演算法下");
- g.addVertex("計算機網路");
- g.addEdge("微積分上", "微積分下");
- g.addEdge("微積分下","機率");
- g.addEdge("機率", "計算機網路");
- g.addEdge("計概", "計組"); g.addEdge("計組", "作業系統"); g.addEdge("作業系統", "計算機網路");
- g.addEdge("計程", "演算法上"); g.addEdge("演算法上", "演算法下"); g.addEdge("演算法下", "作業系統");
- Stack
stack = TopologicalSort.Go(g); - System.out.printf("\t[Info] Topological Sort: %s", stack.pop());
- while (!stack.isEmpty()) {
- System.out.printf("->%s", stack.pop());
- }
- System.out.println();
- }
Supplement:
* [CSIE 1212] Data Structure and Algorithm - 4/9 Graph2
* [ Intro Alg ] Elementary Graph Algorithms - Depth-first search
沒有留言:
張貼留言