DFS 樹的理解


這是一篇對可以用圖的 DFS 樹來解的題的教程/擴展。

在很長一段時間,我並沒有真正理解傳統算法是如何找到橋的。很多題解看起來沒有真正解釋它是如何工作的,很多只是順帶提到它但后迅速地進入實現部分。某一天有人解釋了 DFS 樹是什么, 我才終於正確地理解了它。在此之前,我花了很長時間去理解尋找橋的算法,而且我經常要注意一些細節。現在我已經可以用打字的速度去實現它了。

但是更重要的是,我開始明白同樣的算法該如何用在與橋或多或少無關的題目上。這件事,就像當你有一個黑盒時,你只可以把它當作一個黑盒去使用。但如果你有一個你十分了解的盒子,你可以把它分解,略加改動並把啊用在完全不同的事情上,並且毫無疏漏。

就我而言,DFS 樹是我所知的解決圖的結構問題最好的算法之一。此外,有時在你使用 DFS 樹后,一些可疑的貪心算法的正確性也會變得顯而易見。


考慮一個無向連通圖 G,對它進行深度優先遍歷。它可以用一個遞歸函數來實現,就像這樣:

function visit(u):
     mark u as visited
     for each vertex v among the neighbours of u:
         if v is not visited:
             mark the edge uv
             call visit(v)

以下是實現過程的動畫:
在這里插入圖片描述

我們看一下在第 \(5\) 行被標記的邊。他們構成 G 的以 \(1\) 為根的生成樹。我們稱這些邊為樹邊, 其他的所有邊為回邊

這就是我們圖的 DFS 樹:
在這里插入圖片描述
結論:在生成樹種,圖的回邊連接的都是一個頂點和它的子孫節點。這就是 DFS 樹好用的原因

證明:假設有一條邊 \(u\rightarrow v\),深度優先遍歷已經訪問了 \(u\) 但還沒訪問到 \(v\)。然后

  • 如果深度優先遍歷沿着 \(u\rightarrow v\) 邊由 \(u\) 走向 \(v\),那么 \(u\rightarrow v\) 是一條樹邊。
  • 如果深度優先遍歷沒有沿着 \(u\rightarrow v\)\(u\) 訪問 \(v\),然而此時遍歷到第四步發現 \(v\) 已經被訪問過了。說明 \(v\) 是在遍歷 \(u\) 的一個鄰居節點時對它進行了訪問,這意味着 \(v\)\(u\) 在 DFS 樹中的一個子孫節點。

例如在上面的圖中,節點 \(4\) 和節點 \(8\) 不可能由一條回邊相連因為它們各自都不是另一個的祖先節點,如果由一條邊連接 \(4\)\(8\),遍歷會從 \(4\) 走向 \(8\) 而不是返回 \(2\)

這是 DFS 樹最顯而易見的結論。DFS 樹如此有用因為它簡化了圖的結構。與其去考慮圖中所有種類的邊, 我們此時只需要考慮一棵樹和一些額外的祖先-子孫連邊。這樣的結構十分適於思考和嘗試算法。

原文:https://blog.csdn.net/weixin_43848437/article/details/105133155


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM