最小樹形圖的演算法步驟簡化得說一下就是重複一下三個步驟,直到圖中沒有環為止或者判定有孤立節點無法形成最小樹形圖:
1、刪除自環,除根節點以外,每個點留最小入邊;2、判斷有沒有環;3、如果有環,縮為一點。
現在就從頭開始分析一下這個演算法。
分析第一步:
留每個點地最小入邊,這個沒有問題,也是一種貪心的思想;
為什麼留的是入邊,這也很好解釋,有入邊這個點才能被到達。
分析第二步:
如果這個圖是連通的,每一個點留一條入邊,那麼此時圖中就有n-1條邊,如果有環那麼必定有點之間沒有被串連;
如果有孤立節點,那麼一定是這個圖不連通;
如果沒有環同時每個結點(除根以外)都有前驅,那麼所求的值就是最小樹形圖的權值。
前兩步都比較好理解,關鍵在於第三步。
著重分析一下第三步:
首先,什麼是將一個環縮為一點呢?
就是把這個環看做整體,即一個新的點,然後做一系列的操作(這些操作保證了結果的正確),形成一個“新”的圖,然後再重複這三步;
接著,這一系列的操作是什嗎?
所有環上的所有的點(注意這些點每次迴圈都會被更新,是動態),除了它的最小入邊,其他的入邊的權值都減去最小入邊的權值(後面簡稱它為減法操作),然後箭頭指向“新”的點(也就是這個環)。
其實這個演算法和kruskal很像,如果按照kruskal的思想,如果有一條邊加入到圖中形成環,那麼刪除這條邊,找一條次小的邊,直到符合條件。
那麼同樣的,如果在求最小樹形圖的過程中出現了這樣的情況,我們也一樣要刪除一條邊,在一條邊代替;不同的是,有向圖的邊並不是相等的,即使是起始點相同,還有方向不同,也就是說我們不能簡單刪除這個環上的最大邊或最小邊。
例如,要刪除最大邊,而這個點只有最大邊這一條入邊,那麼這就使得這一點不連通;就算這條邊不是這個點唯一的入邊,那麼刪除它之後還要找替代邊,已知這個環上的邊都是最小入邊,其他入邊只能大於它,刪除最大邊之後再找這個點次小入邊,必定大於環上的其他所有邊,就會存在這樣的情況,某一個較小的邊所對應的點有一條比這個替代的邊小的入邊,如果把這條較小的邊的替代邊加進來,保留原來環上最大邊,刪除較小邊,顯然圖的總權值會小於刪除最大邊的情況,這樣說明刪除最大邊是錯的。那麼如果刪除最小的呢?可是我們無法保證這個最小邊的替代邊比這個環上其他所有邊的代替邊都小,顯然情況很多!
但是,我們要注意一點:
首先我們留下的是最小入邊,並且這是一個環,也就是說,這個環上任意一個點的任意一個入邊,都可以與環上所有點連通(不理解可以畫個圖),那麼如果我們求出這個環的最小入邊,刪除相應的邊,這樣環上所有點依舊連通,並且保證了權值最小。因此,我們要把這個環看做是一個新的點,求這個新的點的最小入邊。
那麼怎麼求這個新的點的最小入邊呢?
那就是要比較環上所有點的所有次小入邊,找出其中最小的,作為這個“新點”的最小入邊(但是這樣很麻煩,接下來的加法操作會說明並解決這個麻煩的問題)。
再有就是為什麼要做減法操作呢?
我認為有兩點個主要原因:
1、每次都找環上每個點的次小邊,很可能環和環之間有組成了一個環,那麼一個點可能有上千個入邊,最後可能就找第i小的邊,顯然很麻煩!巧妙地把環上所有的點都標記成相同的序號,設成一個點,然後設法找這個點的最小入邊即可;
2、我覺得這個減法操作最巧妙!這個我們可以這樣考慮,當形成了一個環的時候,我們要刪除一條環上的邊,加一條環之外的邊,由於每次保留的都是最小入邊,那麼總權值一定是要增加的,如過能讓這個增值最小,那就首先保證了結果的正確,其次保證了每次都是找的最小增值,而增值就是其他入邊減去最小入邊,即“e[i].w
-= in[i]; ”。因此,每次要替換邊的時候,只要加上最小增值即可。接著,我們想到,乾脆就把這個增值付給環的入邊,那麼這個問題就規約到了求圖中除了根節點外的其他節點的最小入邊集,也就是這個演算法的一步!
又一次,我被演算法打動了,是在是太巧妙了!
hdu4009
transfer water就是這樣的一道題,它的分析和解答我寫在下一篇總結中。
下圖是一個最小樹形圖的形成過程: