Krim
、Kruskal
)圖論 (
Graph theory
) 是數學的一個分支,圖是圖論的主要研究對象。 圖 (Graph
) 是由若干給定的頂點及連接兩頂點的邊所構成的圖形,這種圖形通常用來描述某些事物之間的某種特定關係。頂點用於代表事物,連接兩頂點的邊則用於表示兩個事物間具有這種關係。
圖的相關名詞解釋:
圖的表示法:G=(V(G),E(G))
,其中V(G)
表示點集,E(G)
表示邊集;
度:與一個頂點v
關聯的邊的條數稱作該頂點的度,如果是有向圖的話,分爲入度和出度。
圖的分類:有向圖和無向圖;是否爲加權圖;有環圖和無環圖。
圖的表示法:鄰接矩陣和鄰接表。(通常稀疏的圖用鄰接表,稠密的圖用鄰接矩陣,稀疏的圖用鄰接矩陣會非常浪費空間的)
圖的遍歷:深度優先搜索和廣度優先搜索。(DFS
使用棧,將頂點存儲在棧中,頂點是沿着路徑被探索的,存在新的相鄰節點就去探索;BFS
使用隊列,將頂點存入隊列中,最先如隊列的頂點先被探索)
圖遍歷作用:可以用來尋找特定的頂點或尋找兩個頂點之間的路徑,檢查圖是否連通,檢查圖是否含有環等。
圖遍歷的思想:追蹤每個第一次訪問的節點,並且追蹤有哪些節點還沒有被完全探索。對於兩種遍歷方法,都需要指明第一個被訪問的頂點。完全探索一個頂點要求我們查看該頂點的每一條邊。爲了保證算法的效率,務必訪問每個頂點至多兩次。
最小生成樹(Minimum Spanning Tree
,MST
):無向連通圖中邊權和最小的生成樹(最短路徑連接所有節點)。
注意:只有連通圖纔有生成樹,而對於非連通圖,只存在生成森林。
最小生成樹有很多實際問題的應用,例如:要在n
個城市之間鋪設光纜,主要目標是要使這n
個城市的任意兩個之間都可以通信,但鋪設光纜的費用很高,且各個城市之間鋪設光纜的費用不同,因此另一個目標是要使鋪設光纜的總費用最低。這就需要找到帶權的最小生成樹。
有兩個經典的算法可以用來解決最小生成樹問題:Kruskal
算法和Prim
算法。其中Kruskal
算法中便應用了並查集這種數據結構。Prime
算法維護的是頂點的集合,而Kruskal
維護的是邊的集合。
Kruskal
算法此算法可以視爲「加邊法」,即把所有邊按cost
從小到大排序,然後使用並查集依次嘗試合併每個邊:
Kruskal
算法 = 貪心 + 並查集
通過並查集合並後,每個連通分量節點都會有相同的root
,因此檢查所有節點的root
:
root
,說明這個圖只有一個連通分量,是連通圖,返回cost
;root
,說明這個圖有多個連通分量,不是一個連通圖,返回-1
。Krim
算法此算法可以視爲「加點法」,即Kruskal
算法每次添加一個最小的邊,而Prim
算法則是每次添加一個距離已選取節點集最近的點。
流程如下:
S
表示已選取的節點集;A
,放到集合S
中,並更新其他節點到集合S
的最近距離。因爲當前S
中只有一個節點 A
,因此更新爲到節點 A
的距離;S
最近的一個節點 B
,放到集合S
中,並更新其他節點到集合S
的最近距離。也就是節點 i
的距離更新爲 min { adj[A][i], adj[B][i] }
;N
個節點都被選取。實際提交發現,Prim
算法效果遠不如Kruskal
好,原因如下:
connections
),而使用Prim
算法,需要快速得到兩個節點之間的距離。如果每次都直接遍歷connections
,複雜度太高,因此需要先轉換成鄰接矩陣或鄰接表。選擇合適的鄰接矩陣或鄰接表,是解決本題的一個關鍵。PriorityQueue
實現。