相關題目:http://blog.csdn.net/kksleric/article/details/7433909
最大匹配匈牙利演算法:
對於增廣路徑可以用一個遞迴的方法來描述。這個描述不一定最準確,但是它揭示了尋找增廣路徑的一般方法:
“從點A出發的增廣路徑”一定首先連向一個在原匹配中沒有與點A配對的點B。如果點B在原匹配中沒有與任何點配對,則它就是這條增廣路徑的終點;反之,如果點B已與點C配對,那麼這條增廣路徑就是從A到B,再從B到C,再加上“從點C出發的增廣路徑”。並且,這條從C出發的增廣路徑中不能與前半部分的增廣路徑有重複的點。
要完成匈牙利演算法,還需要一個重要的定理:
如果從一個點A出發,沒有找到增廣路徑,那麼無論再從別的點出發找到多少增廣路徑來改變現在的匹配,從A出發都永遠找不到增廣路徑。
最小點覆蓋: 最小覆蓋要求用最少的點(X集合或Y集合的都行)讓每條邊都至少和其中一個點關聯。可以證明:一個二分圖中的最大匹配數等於這個圖中的最小點覆蓋數 (König定理)
(對於點權不一定為1的最小點權覆蓋問題使用費用流求解)
Matrix67給出證明:(做人要厚到 轉貼請註明出處)
匈牙利演算法需要我們從右邊的某個沒有匹配的點,走出一條使得“一條沒被匹配、一條已經匹配過,再下一條又沒匹配這樣交替地出現”的路(交錯軌,增廣路)。但是,現在我們已經找到了最大匹配,已經不存在這樣的路了。換句話說,我們能尋找到很多可能的增廣路,但最後都以找不到“終點是還沒有匹配過的點”而失敗。我們給所有這樣的點打上記號:從右邊的所有沒有匹配過的點出發,按照增廣路的“交替出現”的要求可以走到的所有點(最後走出的路徑是很多條不完整的增廣路)。那麼這些點組成了最小覆蓋點集:右邊所有沒有打上記號的點,加上左邊已經有記號的點。看圖,右圖中展示了兩條這樣的路徑,標記了一共6個點(用 “√”表示)。那麼,用紅色圈起來的三個點就是我們的最小覆蓋點集。
首先,為什麼這樣得到的點集點的個數恰好有M個呢?答案很簡單,因為每個點都是某個匹配邊的其中一個端點。如果右邊的哪個點是沒有匹配過的,那麼它早就當成起點被標記了;如果左邊的哪個點是沒有匹配過的,那就走不到它那裡去(否則就找到了一條完整的增廣路)。而一個匹配邊又不可能左端點是標記了的,同時右端點是沒標記的(不然的話右邊的點就可以經過這條邊到達了)。因此,最後我們圈起來的點與匹配邊一一對應。
其次,為什麼這樣得到的點集可以覆蓋所有的邊呢?答案同樣簡單。不可能存在某一條邊,它的左端點是沒有標記的,而右端點是有標記的。原因如下:如果這條邊不屬於我們的匹配邊,那麼左端點就可以通過這條邊到達(從而得到標記);如果這條邊屬於我們的匹配邊,那麼右端點不可能是一條路徑的起點,於是它的標記只能是從這條邊的左端點過來的(想想匹配的定義),左端點就應該有標記。
最後,為什麼這是最小的點覆蓋集呢?這當然是最小的,不可能有比M還小的點覆蓋集了,因為要覆蓋這M條匹配邊至少就需要M個點(再次回到匹配的定義)。
最小路徑覆蓋: 用盡量少的不相交簡單路徑覆蓋有向非循環圖G的所有結點。解決此類問題可以建立一個二分圖模型。把所有頂點i拆成兩個:X結點集中的i和Y結點集中的i',如果有邊i->j,則在二分圖中引入邊i->j',設二分圖最大匹配為m,則結果就是n-m。
最大獨立集問題: 在N個點的圖G中選出m個點,使這m個點兩兩之間沒有邊.求m最大值.
如果圖G滿足二分圖條件,則可以用二分圖匹配來做.最大獨立集點數 = N - 最大匹配數
最小點覆蓋集=最大點獨立集的補集
最小點支配集=最大匹配數=N-最大獨立集點數
最大團(任意兩點都相連的頂點的集合)=原圖的補圖的最大獨立數
最小邊覆蓋=最大獨立集=點數-最大匹配
1. 從最大匹配出發,通過增加關聯未蓋點的邊獲得最小邊覆蓋集。
2. 從最小邊覆蓋集出發,通過移去相鄰的一條邊獲得最大匹配。
最優匹配KM演算法:
KM演算法是通過給每個頂點一個標號(叫做頂標)來把求最大權匹配的問題轉化為求完備匹配的問題的。設頂點Xi的頂標為A[i],頂點Yi的頂標為B[i],頂點Xi與Yj之間的邊權為w[i,j]。在演算法執行過程中的任一時刻,對於任一條邊(i,j),A[i]+B[j]>=w[i,j]始終成立。KM演算法的正確性基於以下定理:
若由二分圖中所有滿足A[i]+B[j]=w[i,j]的邊(i,j)構成的子圖(稱做相等子圖)有完備匹配,那麼這個完備匹配就是二分圖的最大權匹配。
這個定理是顯然的。因為對於二分圖的任意一個匹配,如果它包含於相等子圖,那麼它的邊權和等於所有頂點的頂標和;如果它有的邊不包含於相等子圖,那麼它的邊權和小於所有頂點的頂標和。所以相等子圖的完備匹配一定是二分圖的最大權匹配。
初始時為了使A[i]+B[j]>=w[i,j]恒成立,令A[i]為所有與頂點Xi關聯的邊的最大權,B[j]=0。如果當前的相等子圖沒有完備匹配,就按下面的方法修改頂標以使擴大相等子圖,直到相等子圖具有完備匹配為止。
我們求當前相等子圖的完備匹配失敗了,是因為對於某個X頂點,我們找不到一條從它出發的交錯路。這時我們獲得了一棵交錯樹,它的葉子結點全部是X頂點。現在我們把交錯樹中X頂點的頂標全都減小某個值d,Y頂點的頂標全都增加同一個值d,那麼我們會發現:
- 兩端都在交錯樹中的邊(i,j),A[i]+B[j]的值沒有變化。也就是說,它原來屬於相等子圖,現在仍屬於相等子圖。
- 兩端都不在交錯樹中的邊(i,j),A[i]和B[j]都沒有變化。也就是說,它原來屬於(或不屬於)相等子圖,現在仍屬於(或不屬於)相等子圖。
- X端不在交錯樹中,Y端在交錯樹中的邊(i,j),它的A[i]+B[j]的值有所增大。它原來不屬於相等子圖,現在仍不屬於相等子圖。
- X端在交錯樹中,Y端不在交錯樹中的邊(i,j),它的A[i]+B[j]的值有所減小。也就說,它原來不屬於相等子圖,現在可能進入了相等子圖,因而使相等子圖得到了擴大。
現在的問題就是求d值了。為了使A[i]+B[j]>=w[i,j]始終成立,且至少有一條邊進入相等子圖,d應該等於min{A[i]+B[j]-w[i,j]|Xi在交錯樹中,Yi不在交錯樹中}。
以上就是KM演算法的基本思路。但是樸素的實現方法,時間複雜度為O(n4)——需要找O(n)次增廣路,每次增廣最多需要修改O(n)次頂標,每次修改頂標時由於要枚舉邊來求d值,複雜度為O(n2)。實際上KM演算法的複雜度是可以做到O(n3)
的。我們給每個Y頂點一個“鬆弛量”函數slack,每次開始找增廣路時初始化為無窮大。在尋找增廣路的過程中,檢查邊(i,j)時,如果它不在相等子圖 中,則讓slack[j]變成原值與A[i]+B[j]-w[i,j]的較小值。這樣,在修改頂標時,取所有不在交錯樹中的Y頂點的slack值中的最小 值作為d值即可。但還要注意一點:修改頂標後,要把所有的slack值都減去d。