最小生成樹
kruskal
kruskal算法步驟:
- 將所有邊按權值從小到大排序
- 將邊按序加入最小生成樹
a. 如果該邊連接的兩點已經屬於一個集合,則舍棄該邊
b. 如果該邊連接的兩點不屬於一個集合,則加入該邊,並將所連兩點用並查集合並 - 當加入n-1條邊后得到的就是該圖的最小生成樹
這么做時間復雜度為\(O(M\log M)\),M為邊的總數,這是給所有邊按權排序的時間復雜度,之后並查集的時間復雜度我不太清楚,大概在\(O(N\log N)\)。
這里用到了貪心思想,也許你會懷疑:為什么這么做是對的?
證明應該分為兩部分:首先證能連成樹,再證這種連法是權值最小的。
首先第一部分十分顯然,一個n個點的連通圖一定能連成一棵樹。
主要來看第二部分:
如果當前邊連接的兩點不在一個集合里,按照kruskal算法應該加入該邊,我們假設舍棄會有更好的結果,最后得到一棵不含該邊的最小生成樹,我們此時再把該邊加入,一定會出現一個環,在該環上不可能所有邊比這條邊小,如果所有邊比這條邊小,那么會與我們在加入該邊時這兩個點時不連通情況矛盾,那么這個環上一定有邊的權值是大於等於該邊的,如果我們用這條邊把權值大於等於該邊的邊替換,得到的生成樹權值不會大於原生成樹,所以能加入時加入這一策略是對的。由此證明了貪心的正確性。
prim
prim算法步驟我懶得寫了,提一嘴時間復雜度是\(O(N\log N)\),接着我簡單證明一下正確性吧
prim算法也是運用貪心的思想。要證明prim算法是對的,關鍵是要證,對於一個集合,離集合最近的邊一定是在最小生成樹上。
算了,懶得證了,哪天有時間再補吧
最大生成樹
顧名思義,最大生成樹就是權值最大的生成樹。
我們很容易想到:按照最小生成樹的做法反過來做不就好了?
但這樣對嗎?
按照以上最小生成樹貪心正確性的證明,我認為這樣是對的。
當然,有一種更保險的做法,把所有邊邊權改為\(X-W\),\(X\)是我們賦的一個很大的數,再跑一遍最小生成樹,得到的結果是\(X*(N-1)-\sum W\),因為\(X*(N-1)\)是一個常數,所以減去該常數取反得到的一定是最小生成樹權值和。