二分圖匹配算法總結

(轉自http://blog.163.com/baobao_zhang@126/blog/static/482523672008631103625967/

一、二分圖最大匹配

    二分圖最大匹配的經典匈牙利算法是由Edmonds在1965年提出的,算法的核心就是根據一個初始匹配不停的找增廣路,直到沒有增廣路爲止。
    匈牙利算法的本質實際上和基於增廣路特性的最大流算法還是相似的,只需要注意兩點:(一)每個X節點都最多做一次增廣路的起點;(二)如果一個Y節點已經匹配了,那麼增廣路到這兒的時候唯一的路徑是走到Y節點的匹配點(可以回憶最大流算法中的後向邊,這個時候後向邊是可以增流的)。
    找增廣路的時候既可以採用dfs也可以採用bfs,兩者都可以保證O(nm)的複雜度,因爲每找一條增廣路的複雜度是O(m),而最多增廣n次,dfs在實際實現中更加簡短。

二、Hopcroft-Karp算法

    SRbGa很早就介紹過這個算法,它可以做到O(sqrt(n)*e)的時間複雜度,並且在實際使用中效果不錯而且算法本身並不複雜。
    Hopcroft-Karp算法是Hopcroft和Karp在1972年提出的,該算法的主要思想是在每次增廣的時候不是找一條增廣路而是同時找幾條點不相交的最短增廣路,形成極大增廣路集,隨後可以沿着這幾條增廣路同時進行增廣。
    可以證明在尋找增廣路集的每一個階段所尋找到的最短增廣路都具有相等的長度,並且隨着算法的進行最短增廣路的長度是越來越長的,更進一步的分析可以證明最多只需要增廣ceil(sqrt(n))次就可以得到最大匹配(證明在這裏略去)。
    因此現在的主要難度就是在O(e)的時間複雜度內找到極大最短增廣路集,思路並不複雜,首先從所有X的未蓋點進行BFS,BFS之後對每個X節點和Y節點維護距離標號,如果Y節點是未蓋點那麼就找到了一條最短增廣路,BFS完之後就找到了最短增廣路集,隨後可以直接用DFS對所有允許弧(dist[y]=dist[x]+1,可以參見高流推進HLPP的實現)進行類似於匈牙利中尋找增廣路的操作,這樣就可以做到O(m)的複雜度。
    實現起來也並不複雜,對於兩邊各50000個點,200000條邊的二分圖最大匹配可以在1s內出解,效果很好:)

三、二分圖最優匹配

    二分圖最優匹配的經典算法是由Kuhn和Munkres獨立提出的KM算法,值得一提的是最初的KM算法是在1955年和1957年提出的,因此當時的KM算法是以矩陣爲基礎的,隨着匈牙利算法被Edmonds提出之後,現有的KM算法利用匈牙利樹可以得到更漂亮的實現。
    KM算法中的基本概念是可行頂標(feasible vertex labeling),它是節點的實函數並且對於任意弧(x,y)滿足l(x)+l(y)≥w(x,y),此外一個概念是相等子圖,它是G的一個生成子圖,但是隻包含滿足l(xi)+l(yj)=w(xi,yj)的所有弧(xi,yj)。
    有定理:如果相等子圖有完美匹配,那麼該匹配是最大權匹配,證明非常直觀也非常簡單,反設其他匹配是最優匹配,它的權必然比相等子圖的完美匹配的權要小。
    KM算法主要就是控制了怎樣修改可行頂標的策略使得最終可以達到一個完美匹配,首先任意設置可行頂標(如每個X節點的可行頂標設爲它出發的所有弧的最大權,Y節點的可行頂標設爲0),然後在相等子圖中尋找增廣路,找到增廣路就沿着增廣路增廣。
    而如果沒有找到增廣路呢,那麼就考慮所有現在在匈牙利樹中的X節點(記爲S集合),所有現在在匈牙利樹中的Y節點(記爲T集合),考察所有一段在S集合,一段在not T集合中的弧,取
    delta =  min {l(xi)+l(yj)-w(xi,yj),xi ∈ S, yj ∈ not T}
    明顯的,當我們把所有S集合中的l(xi)減少delta之後,一定會有至少一條屬於(S,not T)的邊進入相等子圖,進而可以繼續擴展匈牙利樹,爲了保證原來屬於(S,T)的邊不退出相等子圖,把所有在T集合中的點的可行頂標增加delta。
    隨後匈牙利樹繼續擴展,如果新加入匈牙利樹的Y節點是未蓋點,那麼找到增廣路,否則把該節點的對應的X匹配點加入匈牙利樹繼續嘗試增廣。
    複雜度分析:由於在不擴大匹配的情況下每次匈牙利樹做如上調整之後至少增加一個元素,因此最多執行n次就可以找到一條增廣路,最多需要找n條增廣路,故最多執行n^2次修改頂標的操作,而每次修改頂標需要掃描所有弧,這樣修改頂標的複雜度就是O(n^2)的,總的複雜度是O(n^4)的。
    事實上我現在看到的幾個版本的實現都是這樣實現的,但是實際效果還不錯,因爲這個界通常很難達到。
    對於not T的每個元素yj,定義鬆弛變量slack(yj) = min{l(xi)+l(yj)-w(xi,yj),xi ∈ S},很明顯的每次的delta=min{slack(yj),yj∈ not T},每次增廣之後用O(n^2)的時間計算所有點的初始slack,由於生長匈牙利樹的時候每條弧的頂標增量相同,因此修改每個slack需要常數時間(注意在修改頂標後和把已蓋Y節點對應的X節點加入匈牙利樹的時候是需要修改slack的)。這樣修改所有slack值時間是O(n)的,每次增廣後最多修改n次頂標,那麼修改頂標的總時間降爲O(n^2),n次增廣的總時間複雜度降爲O(n^3)。事實上我這樣實現之後對於大部分的數據可以比O(n^4)的算法快一倍左右。

四、二分圖的相關性質

    本部分內容主要來自於SRbGa的黑書,因爲比較簡單,僅作提示性敘述。
    (1) 二分圖的最大匹配數等於最小覆蓋數,即求最少的點使得每條邊都至少和其中的一個點相關聯,很顯然直接取最大匹配的一段節點即可。
    (2) 二分圖的獨立數等於頂點數減去最大匹配數,很顯然的把最大匹配兩端的點都從頂點集中去掉這個時候剩餘的點是獨立集,這是|V|-2*|M|,同時必然可以從每條匹配邊的兩端取一個點加入獨立集並且保持其獨立集性質。
    (3) DAG的最小路徑覆蓋,將每個點拆點後作最大匹配,結果爲n-m,求具體路徑的時候順着匹配邊走就可以,匹配邊i→j',j→k',k→l'....構成一條有向路徑。

五、穩定婚姻問題

    穩定婚姻問題是一個很有意思的匹配問題,有n位男士和n位女士,每一個人都對每個異性有一個喜好度的排序,代表對他的喜愛程度,現在希望給每個男士找一個女士作配偶,使得每人恰好有一個異性配偶。如果男士u和女士v不是配偶但喜歡對方的程度都大於喜歡各自當前配偶的程度,則稱他們爲一個不穩定對。穩定婚姻問題就是希望找出一個不包含不穩定對的方案。
    算法非常簡單,稱爲求婚-拒絕算法,每位男士按照自己喜歡程度從高到低依次給每位女士主動求婚直到有一個女士接受他,對於每個女士,如果當前向她求婚的配偶比她現有的配偶好則拋棄當前配偶,否則不予理睬,循環往復直到所有人都有配偶。有趣的是,看起來是女士更有選擇權,但是實際上最後的結果是男士最優的(man-optimal)。
    首先說明最後匹配的穩定性,隨着算法的執行,每位女士的配偶越來越好,而每位男士的配偶越來越差。因此假設男士u和女士v形成不穩定對,u一定曾經向v求過婚,但被拒絕。這說明v當時的配偶比u更好,因此算法結束後的配偶一定仍比u好,和不穩定對的定義矛盾,類似的,方式我們考慮最後一個被拋棄的男士和拋棄這位男士的女士,不難得出這個算法一定終止的結論。
    如果存在一個穩定匹配使得男士i和女士j配對,則稱(i,j)是穩定對。對於每個男士i,設所有穩定對(i,j)中i 最喜歡的女士爲best(i),則可以證明這裏給出的算法對讓每位男士i與best(i)配對。對於所有男士來說,不會有比這更好的結果了,而對於女士則恰恰相反,對於她們來說不會有比這更糟的結果了,因此這個算法是男士最優的。
    算法一定得到穩定匹配,並且複雜度顯然是O(n^2),因爲每個男士最多考慮每個女士一次,考慮的時間複雜度是O(1),當然了,需要作一定的預處理得到這個複雜度。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章