# Week 11 # Question :::info :::spoiler Click to Open Question ![](https://i.imgur.com/iTv6rZ3.png) ![](https://i.imgur.com/dw9aicb.png) ![](https://i.imgur.com/YoD5hbL.png) ## Check - [ ] Q1 - [ ] Q2 - [ ] Q3 - [ ] Q4 - [ ] Q5 - [ ] Q6 - [ ] Q7 ::: # Answer ## Q1 > - [name=xian] :::spoiler **【題目】** A DFS forest can be generated by perform DFS on a directed graph. There are 4 types of edges in a DFS forest: `tree edge`, `forward edge`, `back edge` and `cross edge`. Modify DFS so that it can determine the type of each edge. ::: **【edge的定義】** * Tree Edge (GRAY to WHITE) * Edges in the DFS forest * Found when encountering a new vertex 𝑣 by exploring 𝑢, 𝑣 * Back Edge (GRAY to GRAY) * 𝑢, 𝑣 , from descendant 𝑢 to ancestor 𝑣 in a DFS tree * Forward Edge (GRAY to BLACK) * 𝑢, 𝑣 , from ancestor 𝑢 to descendant 𝑣. Not a tree edge. * Cross Edge (GRAY to BLACK) * Any other edge between trees or subtrees. Can go between vertices in same DFS tree or in different DFS trees. **【解題思路】** 利用塗色的方法解決問題,根據DFS Property我們可以將遇到不同顏色看做是edge的分類: * White(沒走過): tree edge * Gray(走進去還沒出來): back edge * Black(走出來了):forward edge or cross edge * u.d < v.d $\Rightarrow$ forward edge * u.d > v.d $\Rightarrow$ cross edge 因此我們可以在DFS Algorithm中加入判斷式,獲得我們要的答案。 **【變數定義】** * $c[u]$:node u目前的顏色 * $d[u]$:node u第一次進入的時間 * $p[u]$:node u 第一次被探訪時的前一個node **【蘇都扣】** ```cpp= DFS(G) let v[] be the node of G and Adj[] be the Adjacency list of the G let all value in c[] be white //c[u]: node u 目前的顏色 time = 0 for u in V: if c[u] == white Visit(u) Visit(u) c[u] = gray d[u] = ++time for v in Adj[u]: if c[v] == white: p[v] = u Visit(v) (u,v) is a tree edge else if c[v] == gray: (u,v) is a back edge else //black if d[u] < d[v]: (u,v) is a forward edge else: (u,v) is a cross edge c[u] = black ``` ## Q2 > - [name=LXS] :::spoiler 【題目】 Show how the procedure STRONGLY-CONNECTED-COMPONENTS works on the graph of Figure 22.6. Specifically, show the finishing times computed in line 1 and the forest produced in line 3. Assume that the loop of lines 5-7 of DFS considers vertices in alphabetical order and that the adjacency lists are in alphabetical order. ::: * Strongly Connected Components ``` Strongly-Connected-Components(G) Call DFS(G) to computing f[u] for each u \in V. Compute GT. Call DFS(GT) but consider the vertices in order of decreasing f[u] computed in line 1. Output the vertices of each tree in the DFS forest formed in line 3 as a separate SCC. ``` * Call DFS(G) to computing f[u] for each $u \in V$. | Vertices | Discover d\[u\] | Finish f\[u\] | | -------- | --------------- | ------------- | | q | 1 | 16 | | r | 17 | 20 | | s | 2 | 7 | | t | 8 | 15 | | u | 18 | 19 | | v | 3 | 6 | | w | 4 | 5 | | x | 9 | 12 | | y | 13 | 14 | | z | 10 | 11 | * Graph of $G^T$ ```graphviz digraph { ordering=out; node [shape=circle] q -> y s -> w s -> q t -> q u -> r v -> s w -> q w -> v x -> t x -> z y -> t y -> u y -> r z -> x } ``` * Call $DFS(G^T)$ but consider the vertices in order of decreasing f[u] computed in line 1. * $\text{f[ ] in descending order.}$ | Vertices | Discover d\[u\] | Finish f\[u\] | | -------- | --------------- | ------------- | | r | 17 | 20 | | u | 18 | 19 | | q | 1 | 16 | | t | 8 | 15 | | y | 13 | 14 | | x | 9 | 12 | | z | 10 | 11 | | s | 2 | 7 | | v | 3 | 6 | | w | 4 | 5 | * $DFS(G^T)$ | Vertices | Discover d\[u\] | Finish f\[u\] | | -------- | --------------- | ------------- | | r | 1 | 2 | | u | 3 | 4 | | q | 5 | 10 | | t | 7 | 8 | | y | 6 | 9 | | x | 11 | 14 | | z | 12 | 13 | | s | 15 | 20 | | v | 17 | 18 | | w | 16 | 19 | 由此可得到五棵樹: :::spoiler ![](https://i.imgur.com/ZdYomQy.png) ::: ## Q3 > - [name=Mark] > **前情提要** G = (V, E) is semi-connected => for all pairs of vertices u, v in V, we have u->v or v->u. **思路** 1. 先對`graph`做求有向圖的SCC的`Tarjan's Algorith`得出SCC,$O(V+E)$ 2. 把SCC接起來成新的`graph`(已變成DAG)->`gN` 3. 對`gN`做`DFS()`檢查是否為`semi-connected`,$O(V+E)$,查看是否為線性鏈 **蘇都扣** 【step 1,2】 ```cpp= //dfn[] 為vertex n的時間戳 //low[] 為n或n子樹能追溯到最早stack中的時間戳 //component[] 每個點對應到的SCC收縮成的點 let g[] be the Adjacency list of the G //adjacency list let all value in dfn[N], component[N], low[N] be zero create an empty Stack S int T = 0 //時間戳記 int C = 0 //SCC component個數 for u = 0 to g.size(): if(!dfn[u]) DFS(u) DFS(u){ dfn[u] = low[u] = ++T S.push(u) for v in g[u]: if(v is not visited): //尚未被訪問到 DFS(v) low[u] = min(low[u], low[v]) else if(v is in S): low[u] = min(low[u], dfn[v]) if(dfn[u] == low[u]): C++ do{ t = S.pop() component[t] = C }while(t != u); } ``` 【step 3】 ```cpp= //承上 visit = [] //紀錄是否走過 answer = false flag = false DFS_check(index){ if(flag): return answer visit[index] = true for i in g[index]: if(visit[i]) continue; else if(!visit[i] && component[i] == component[index]): DFS_check(i) else if(!visit[i] && component[i] == component[index] + 1): DFS_check(i) else: flag = true answer = false if(!flag and C == component[index]): flag = true answer = true else: flag = true answer = false } ``` ans: $DSF\_check(root)_\#$ **證明** 如果這個圖是 semi-connected,對於任意的$(v_1,v_2)$,都會有 path $:v_1\rightarrow \cdots \rightarrow v_2$,假設 $U_1,U_2$ 是他們的SCCs,如果有 path 從 $U_1\ 到\ U_2$,那麼一定也會有 path 從 $v_1\ 到\ v_2$,因為 $U_1,U_2$ 裡的 node 都是 strongly-connected。 ## Q4 > - [name=songchiu] 題意:張貴雲教授教的「用stack解DFS」可否拿來處理Topo Sorting、Strongly-Connected-Component **【Topological Sorting】** 結論:**可以,但要修改**。 原本是沒辦法的,因為順序會有差,以ppt裡的圖為例: ![](https://i.imgur.com/fUWycpP.jpg =150x150) 何老師的作法,DFS會求出:AFEGDCB 張老師的作法,DFS會求出:AGEDBCF 很明顯的,E不應該在F的前面,因此不適用 會發生這樣的狀況因為較後面被走訪的點,先被pop出來了 因此我們要將該DFS修改一下,加入stack的$u$點先不要pop出來,待它的子小孩都過且離開stack後,再將$u$點pop出來 當每個子小孩離開stack時,順便將它的離開時間紀下來。待全部完成後,把紀下來的時間倒過來,即為topo sort的時間 附上蘇都扣來參考一下: ```cpp= TopoSort(){ Time[], time_counter = 0//初始化時間 for u in G if stack is empty and u not reached mark u as reached, push into stack while stack is not empty //Traverse the tree has_child = 0 for v in Adj[vertex at top of stack] if v not reached mark v as reached, push into stack has_child = 1 if has_child = 0 Time[vertex at top of stack] = ++time_counter pop stack } ``` :::spoiler 寫錯的版本 ![](https://i.imgur.com/Mo7wE8F.png) **證明** $\text{Let (u,v) be an edge. We shall show } finish\_time(v) < finish\_time(u) \text{ so that the ordering is correct}$ $\text{In DFS, there are two cases.}$ $\text{Case1: u is visited before v}$ $\text{Case2: v is visited before u}$ $\text{In Case 1, u cannot finish before DFS is performed on all its neighbors.}$ $\text{Since v is a neighbor of u , we must have }$ $discovery\_time(u) < discovery\_time(v) < finish\_time(v) < finish\_time(u)$ $\text{In Case 2, v must have finished before u starts. Otherwise the graph contains a cycle.}$ $\text{Thus, } finish\_time(v) < discovery\_time(u) \rightarrow finish\_time(v) < finish\_time(u)$ $\text{Both cases show }finish\_time(v) < finish\_time(u)_\#$ $\text{Note: discovery_time means the vertix enter stack}$ $\text{Note: finish_time means the vertix pop out stack}$ [Ref 清大資工演算法ppt](http://www.cs.nthu.edu.tw/~wkhon/ds/ds11/lecture/lecture12.pdf) ::: **【Strongly Connected Components】** 結論:**可以,但也要修改**。 在此說明常用的SCC解法: ```graphviz digraph { ordering=out; node [shape=circle] a -> b b -> c c -> a } ``` 假設從$A$開始找,$A$的時間為1;接著向下找,依序找到$B$、$C$; 接著$C$就會走回$A$,但發現$A$走過了,就會將$A=1$的時間傳給$C$,接著再依序往上傳給$B$ (利用遞迴式回傳值的方式) 因此我們在一張圖中,看到有幾種不同的時間,就是有幾個$SCC$ 但是第二種解法,它用stack來處理 假設有一點$u$,在準備被走訪前,先被丟到stack 走訪時被從stack取出,走訪後就沒辦法再回頭改它的值了 由於我們沒辦法回頭更新$u$,因此這個方法不適合拿來解$SCC$ 但還是有辦法解的,只要稍微修改一下就行了 跟剛剛的很像,但多拿一個stack $S$來紀錄一下當時走訪過哪些點 之後再透過一個vector $SCC$ 來存放,擁有相同counter值的,會被放到同個vector元素裡 這樣就可以找出它們是不是SCC的關係了 ```cpp= findSCC(){ counter = 0//初始化SCC個數 for u in G //run 1st DFS if stack is empty and u not reached mark u as reached, push into stack while stack is not empty Traverse the tree and store each vertex by exit time into S while S is not empty //run 2nd DFS u = S's top if stack is empty and u not reached mark u as reached, push into stack counter++ while stack is not empty SCC[counter].push_back(vertex at top of stack) for v in Adj[vertex at top of stack] if v not reached mark v as reached, push into stack return SCC } ``` ## Q5 > - [name=songchiu] <!-- $\text{By Theorem 23.1, We remove (u,v) and draw a cut cross (u,v). }$ $\text{Now, our strategy is choose a light-weight edge,}$ $\text{because (u,v) is in this MST originally, then (u,v) is a light edge.}$ --> 假設原本的圖形是這樣,紫色的邊構成$MST \; T$ ![](https://i.imgur.com/l8jczis.jpg =250x150) 接著將$(u, v)$剪掉,此時是兩個分開的connected component 我們需要再找個權重較低的邊,把圖重新組回$MST \; T'$ ![](https://i.imgur.com/5Skp03M.jpg =250x150) 假定$(x, y)$是權重較小的邊 ($weight(x,y) \leq weight(u,v)$) 它能使圖形再次回到$MST$(因為$(x, y)$已經是當前最小) ![](https://i.imgur.com/OYAo5V9.jpg =250x150) :::spoiler Theorem 23.1 ![](https://i.imgur.com/yZAdTjy.jpg) ::: 會得出這樣的結論,是依據Theorem 23.1 當把$(u, v)$剪掉後,在它的crossing edge當中,可以找到一個最輕邊$(x, y)$ 這個最輕邊$(x, y)$也會是MST裡的一條邊 用數學式來證就是: 因為 $weight(x,y) \leq weight(u,v)$ 所以 $weight(T') \leq weight(T)−weight(u,v)+weight(x,y)$ $weight(T') \leq weight(T)$ 因此若$T$是$MST$,$T'$也會是$MST$ ## Q6 > - [name=chung] :::spoiler **【題目】** Let e be a maximum-weight edge on some cycle of connected graph G = (V, E). Prove that there is a minimum spanning tree of G’ = (V, E – {e}) that is also a minimum spanning tree tree of G. That is, there is a minimum spanning tree of G that does not include e. ::: **【Proof】** 利用反證法,假設 T 是一顆隨意的生成樹,不包含上述被剪掉的最大weight的邊 e・由於樹的特性,可以得知點之間一定有路徑互相連接,假設這條路徑為P,P 一定會穿過 S 與 V − S 兩個子集,假設連接兩個 set 的邊為 e',e' 連接的兩個點分別為 V' 與 W'・將 e' 替換成 e,生成新的樹 T',由於 e > e',因此 T' 的權重勢必會比較大,而 T' 的每個點也都會有路徑相連,同時 T' 是以 e' 替換 e 形成,並沒有引進新的邊,因此也不會出現 cycle,故得證 T' 的權重大於 T,T'不是最小生成樹,故最小生成樹不會包含e。 ## Q7 > - [name=yee] :::spoiler **【題目】** Show that a graph has a unique minimum spanning tree if, for every cut of the graph, there is a unique light edge crossing the cut. Show that the converse is not true by giving a counterexample. ::: **【解題思路】** 透過反證法,先假設有兩棵$MST$,分別為 $T、T'$ 先從 $T$ 中隨機移除一條邊 $e$,產生兩個$T$的子集 $S、V-S$ 因為$e\ cross\ cut(S,V-S)$ ,由 $Q5$ 可知 $e$ 為 $cut(S,V-S)$中的唯一最輕邊 再假設 $x$ 為 $T'$ 且穿過 $cut(S,V-S)$ 由於穿過 $cut(S,V-S)$ 的最輕邊是唯一 即代表 $e$ 與 $x$ 為同一條邊,所以 $e$ 也屬於 $T'$ 又因 $e$ 為隨機選擇,代表所有於 $T$ 上的邊也於 $T'$ 上 即可證明 $MST$ 是唯一 **【Counterexample】** 若一 $Graph$ 存在唯一 $MST$,$cut(S,V-S)$ 中未必存在唯一最輕邊 ![](https://i.imgur.com/YwSnnYn.png) 由上圖可知,$AB\ 與\ BC$ 皆為最輕邊