演算法導論第三版 22.3 深度優先搜尋 課後題答案全解析
22.3 深度優先搜尋:
1. 問有向圖和無向圖可能存在的三種顏色的點到點之間的邊。
這個問題比較簡單,直接上傳原版答案,但是要注意,有向圖中存在黑色點到其他點的邊,雖然黑色點是已經搜尋結束的,但是這樣的邊始終存在。
有向圖:
無向圖:
2. 答案如下:
注意其中數字沒有重複的,無論如何time值都會+1。
3. 給出括號結構,題目中要求的是22-4即下圖:
因此括號結構應該為(((())))(()),作者認為參考答案解釋有所不妥。
4. 與22.2中證明一位儲存顏色類似。
5. 根據括號化定理可輕鬆證明,略。
6. 證明:在無向圖中,根據深度優先搜尋是先探索(u,v)還是先探索(v,u)來將邊(u,v)分為樹邊或者後向邊,與根據分類列表中的四種類型的次序進行分類是等價的。
證明:首先分類列表中的四種類型,樹邊、前向邊、後向邊、橫向邊,在無向圖中只有樹邊和後向邊。如果u、v之間的這條邊,若從u→v方向進行搜尋,若先發現的u,則是一條樹邊,然後v也被發現;若先發現的v,則u是v的祖先結點,因此這是一條後向邊。和分類一致,得證!
7. 用Stack來實現深度優先搜尋:
DFS(G){ for each vertex u belong G.V u.color = WHITE u.pai = NIL time = 0; for each vertex u belong G.V if u.color ==WHITE DFS_VISIT(G,u) } DFS_VISIT(G,u){ time = time + 1 u.color = GRAY u.d = time while stack != empty v = stack.pop() time = time +1 v.d = time v.color = GRAY for each vertex w adjacent to v if w.color == WHITE stack.push(w) time = time +1 v.f = time time = time +1 u.f = time }
用一個棧來代替迴圈,與網路大部分虛擬碼不同的是,該處加入了time來標記u.d和u.f。(該部分虛擬碼迴圈和條件的判斷格式與演算法導論書一致)
8. “有向圖G包含一條從結點u到結點v的路徑,並且在深度優先搜尋中u.d<v.d,則結點v是結點u在深度優先森林中的一個後代。”為這句話找出一個反例。
如圖左中右三點,從中間點開始深度優先搜尋,先找到左邊的點,再找到右邊的點,深度優先森林中右邊的點不是左邊點的後代,雖然在圖中存在一條從左邊的點到右邊的點的路徑。
9. “如果有向圖G包含一條從結點u到結點v的路徑,則任何對圖G的深度優先搜尋都將導致v.d<=u.f。”為這句話舉出一個反例。
仍運用此圖,如果深度優先搜尋從中間點開始,先搜尋右邊點再搜尋左邊點,將會出現右邊點的
10. 修改深度優先搜尋的虛擬碼,讓其打印出有向圖G的每條邊及其分類。
深度優先森林有樹邊,後向邊,前向邊,橫向邊
(修改為粗體)
DFS(G)
for each vertex u belong to G.V
u.color = WHITE
u.pi = NIL
time = 0
for each vertex u belong to G.V
if u.color == WHITE
DFS-VISIT (G,u)
DFS-VISIT(G,u)
time = time + 1
u.d = time
u.color = GRAY
for each v belong to G:Adj[u]
if v.color == WHITE
輸出(u,v)為樹邊
v.pi = u
DFS-VISIT(G,v)
if v.color == GRAY
輸出(u,v)為後向邊
if v.color == BLACK && v.f > u.d
輸出(u,v)為前向邊
if v.color == BLACK && v.f < u.d
輸出(u,v)為橫向邊
u.color = BLACK
time = time + 1
u.f = time
如修改,在遍歷到一個邊的時候對v的color屬性和f屬性進行判斷,將不同的邊進行輸出。如果是無向圖,與有向圖相比,無向圖四種邊沒有什麼區別,因此不需要進行調整。
11. 有向圖的一個結點u怎樣才能成為深度優先樹中的唯一結點,即使結點u同時有入邊和出邊.
a) 首先結點u是一個自迴圈且只有自迴圈的結點。
b) 當一個點u出邊指向的點已經被搜尋結束屬於其他深度優先樹,並且接下來搜尋點u,那麼將會出現u是深度優先樹中的唯一結點。
12. 證明略,內容在22.5強連通分支有詳細講解。
修改程式碼標記深度優先樹,算導中DFS演算法中,從圖中找到一個新的結點的時候標記為x,然後在DFS-VISIT中將遍歷到的每個white結點也標記為x。再回到DFS再找到一個新節點的時候標記為x+1,迴圈以上操作。
13. 判斷圖是不是單連通圖。
首先進行拓撲排序。然後為每個結點維護一個連結串列,儲存入度為0的祖先結點。
然後為每個點計算這些表根據拓撲排序從小到大的順序。然後如果我們有一結點,它的兩個以上的前驅結點的連結串列中包含同一個入度為0的祖先結點,我們可以知道,這不是單連通圖了。相反,如果我們發現每個結點的前驅包含不相同的入度為0的結點,我們就可以判斷這個圖是一個單連通圖。