spanning tree
spanning tree / spanning forest
「生成樹」。從一張圖取出一棵樹,包含圖上所有點。可能有許多種。
當一張圖完全連通,則擁有生成樹。當一張圖不連通,則沒有生成樹,而是擁有許多棵「生成子樹」構成的「生成森林」。
生成樹的權重,是樹上每條邊的權重總和。
minimum spanning tree
「最小生成樹」。權重最小的生成樹。可能有許多種。
minimum spanning tree: Kruskal's algorithm
用途
求出無向圖的其中一棵最小(大)生成樹。若是圖不連通,則是求出其中一叢最小(大)生成森林。
想法
一、一個單獨的點,視作一棵最小生成子樹MSS。
二、兩棵MSS連結成一棵MSS,以兩棵MSS之間權重最小的邊進行連結,顯然是最好的。
三、三棵MSS連結成一棵MSS,以其中兩棵MSS之間權重最小的邊進行連結,才連結第三棵,總是比較好。
點的視角:不斷連結兩棵MSS、合併兩棵MSS,得到最小生成樹(森林)。
邊的視角:依序以權重最小、次小、……的邊,嘗試連結各棵MSS,得到最小生成樹(森林)。
演算法
一、圖上每一個點,各自是一棵最小生成子樹MSS。 二、圖上所有邊,依照權重大小,由小到大排序。 三、嘗試圖上所有邊,作為最小生成樹(森林)的邊: 甲、兩端點分別位於兩棵MSS,也就是產生了橋: 用這條邊連結兩棵MSS,合併成一棵MSS。 這條邊是最小生成樹(森林)上的邊。 乙、兩端點皆位於同一棵MSS,也就是產生了環: 捨棄這條邊。
尋找最小生成樹的過程:
尋找最大生成樹的過程:
時間複雜度
一、排序圖上所有邊。O(ElogE)。
二、連結MSS,採用「disjoint-sets forest」。O(Eα(V))。
總時間複雜度O(ElogE)。
如果兩點之間有多條邊,預先以graph traversal掃描一次所有邊,保留權重最小的邊,仍可求得正確答案。兩點之間只剩下一條邊,邊數至多C(V,2) = V(V-1)/2 = O(V²)條。時間複雜度O(ElogE)可以改寫成O(ElogV²) = O(2ElogV) = O(ElogV)。
minimum spanning tree: Prim's algorithm
用途
求出無向圖的其中一棵最小(大)生成樹。
演算法
仿效Dijkstra's algorithm。
差異:Dijkstra's algorithm屢次找不在樹上、離根最近的點,Prim's algorithm屢次找不在樹上、離樹最近的點。
另一個差異:選擇特定一點作為起點,得到不同的最短路徑樹;選擇任意一點作為樹根,得到相同的最小生成樹。
時間複雜度
圖的資料結構為adjacency matrix是O(V²);圖的資料結構為adjacency lists仍是O(V²)。
如同Dijkstra's algorithm,運用各種極值資料結構得以降低時間複雜度。
UVa 10034 10147 10307 10397 10842
© 2010 tkcn. All rights reserved.
minimum spanning tree: Borůvka's algorithm
用途
求出無向圖的其中一棵最小(大)生成樹。若是圖不連通,則是求出其中一叢最小(大)生成森林。
演算法
一、圖上每一個點,各自是一棵最小生成子樹MSS。 二、每棵MSS同時找權重最小、索引值最小的聯外邊,相互連接。 口、聯外邊是MSS之間的邊,不是MSS之內的邊。 口、聯外邊可能重複,無妨。 口、聯外邊顯然不會形成環。 三、重複步驟二,直到形成最小生成樹(森林)。
找權重最小的聯外邊,以得到最小生成樹;當權重一樣小,則找索引值最小的聯外邊,以避免聯外邊形成環。聯外邊的索引值,可以改成聯外邊的兩端點索引值。
證明很簡單:圖上任意一個環,環上權重最大、索引值最大的邊,絕不會被選中。過程中無法形成環,只會形成樹。每一點都聯外,權重又最小,所以是最小生成樹。
時間複雜度
一、每回合尋找權重最小、索引值最小的聯外邊。O(V+E)。
二、連接MSS。採用「disjoint-sets forest」,每回合每個點都呼叫了merge與find,森林結構維持在最佳狀態,merge與find的總時間複雜度,從O(Eα(V))降為O(E)。
三、回合數。最差情況:每回合MSS兩兩成對互連,MSS總數量僅下降一半,共logV個回合。平均情況:圖上的邊呈隨機分布,僅1至2個回合。【待補證明】
最差時間複雜度O((V+E)logV),通常簡單寫成O(ElogV)。平均時間複雜度O(V+E)。
minimum spanning tree: Edmonds' algorithm
用途
求出有向圖的其中一棵最小(大)生成樹。
有向圖上,以權重最小的邊,連結兩棵有向MSS,不見得形成有向MSS。直接套用無向圖的演算法,邊的方向亂七八糟,無法形成有向生成樹。必須設計其他演算法。
想法
生成樹的基本概念是:連接圖上各點的樹。從這個概念下手,並且考慮邊的方向性,得到兩個粗糙的演算法:
有向圖上,每一個點,如果要被連結到,都要至少有一條出邊,除了樹葉以外。 每一個點,找權重最小的出邊,會比較好。
有向圖上,每一個點,如果要被連結到,都要剛好有一條入邊,除了樹根以外。 每一個點,找權重最小的入邊,會比較好。
出邊有許多條,入邊只有一條,從入邊下手比較容易。
樹根是個例外,樹根沒有入邊。但是我們可以假定我們已經知道最小生成樹的樹根是哪個點,如此就不必顧慮例外了。設計好演算法之後,用試誤法嘗試各種樹根即可。
minimum arborescence
預先指定樹根的有向最小生成樹。個人感覺這個詞彙不太討喜。
水母【尚無正式名稱,因為像水母就把它叫做水母】
運氣好的時候,各點的最小入邊,剛好形成一棵生成樹,而且是最小生成樹。
運氣普通的時候,各點的最小入邊,通常形成許多隻水母。
各點各取一條入邊,一旦入邊們形成環,此環一定只有出邊、沒有入邊。環與出邊,形成一個特別的圖:很多棵樹,一個環串起了樹根。又像是太陽、又像是水母。
把水母改裝成最小生成子樹
最小生成樹不得有環。水母有環,是不合格的。
水母是權重最小的連結方式,最小生成樹的權重則略高、等高於水母。使用窮舉法,嘗試拆除水母的每一條邊,並且更改為另一條邊,從中找到權重增加最少的邊。
一、更改水母環的邊: 甲、新邊是由其他水母連入:水母環消失。變成其他水母腳。很好! 乙、新邊是由自身水母環連入:水母環變小。連結權重無故變大,不可取。 丙、新邊是由自身水母腳連入:水母環變大。多了一些點可供聯外。 二、更改水母腳的邊: 水母環不變,連結權重無故變大,不可取。
有好處的只有一甲、一丙。歸納出:只需要更改水母環的邊,讓水母環消失或者變大,從中選擇權重增加最少的拆除方式。
演算法
水母環的入邊,全部看過一遍,找到權重增加最少的入邊。
已經看過的入邊,修改成權重增加量,然後收縮水母環,就不用看第二遍了。
壹、刪去所有自環:自己連向自己的邊。 貳、圖上每一點嘗試作為樹根。 一、刪去樹根的全部入邊。也可以將權重設定為無限大。 二、判斷樹根能不能連到圖上各點。否則生成樹不存在。 三、重複以下步驟,直到形成生成樹為止: 甲、每一個點,找出權重最小的入邊。O(V+E) 形成一群水母。 乙、調整水母環的入邊的權重,修改成權重增加量。O(V+E) w(a, x) -= w(å, x), x是水母環上一點。 åx是x點的最小入邊,也是水母環上的邊。 ax是x點的其他入邊。 丁、收縮水母環,成為一點。O(V+E)
Kruskal's algorithm連結多個MSS。一旦發現造成環的邊,就直接捨棄;一旦發現造成橋的邊,就一定保留。
Edmonds' algorithm連結多隻水母。總是留下造成環的邊(形成水母環),並且嘗試各種打開環的方式:有時候擴大水母環,有時候兩隻水母連結成一隻水母。
時間複雜度
一、每回合找出各點的最小入邊。O(V+E)。
二、回合數。最差情況是每回合產生一個水母,水母環只有兩點。水母環收縮之後,整張圖只減少一個點。圖上有V個點,最多收縮V-1次水母環,總共V-1個回合。
三、窮舉V個點,嘗試作為樹根。
時間複雜度O(VVE)。
演算法
窮舉樹根,再仿效Dijkstra's algorithm,時間複雜度O(V³)。有差異的地方,不影響時間複雜度:
一、縮環最多V-1次(兩點縮成一點)。縮環得到的新點,最多V-1個。總點數最多2V,仍是O(V)。
二、縮環,採用disjoint-sets forest。O(Eα(V))。
如同Dijkstra's algorithm,運用各種極值資料結構得以降低時間複雜度。
UVa 11183