匈牙利演算法又稱 Kuhn-Munkres 演算法 (簡稱 KM) 是用於尋找二分圖最大權匹配。在打競程時,不常遇到這類題目,就算遇到也算是很好發揮,把問題轉化再套模板即可。然而,其原理卻相當複雜,理解原理後也有利於理解如何轉化匹配類型的題目,因此這篇會把整套原理說明清楚
閱讀之前可以先看前篇三篇匹配與霍爾定理、Kőnig 定理、擴充路徑演算法,有利於了掌握匹配問題的脈絡
有一個農業公司擁有 塊玉米田與 個加工廠。每一塊田地可以生產的玉米產量各有不同,每一個加工廠的產能也不同。從第 塊田地運送到第 個加工廠可以賺到 元。公司想要找一組好的匹配使獲利最大化
我們可以把他們的關係化成二分圖,田地 、加工廠 ,將獲利 作為權重擺在邊 上,這問題就會轉化成二分圖最大權匹配問題
承上述情境,有一天政府認為玉米產量過剩,因此希望可以付錢使停止生產與製造。若公司同意不繼續在第 塊田地種玉米,那麼政府就會付 元給公司;若公司同意不繼續在第 個加工廠生產產品,那麼政府就會付 元給公司。如果 ,則公司會繼續使用邊 來獲利,不會接受政府的錢。為了可以停止生產與製造,政府必須花費 對於所有 。政府希望可以最小化
我們稱這問題是一個最小權點覆蓋問題
一組權重覆蓋,是一組標記 (label) 的選擇,分別是 與 。這些組選擇會使得 。而一個覆蓋 的花費 (cost) 是 。最小權點覆蓋 (minimum weighted cover) 就是指其中最小的花費。對於一個有最大權完美匹配 的二分圖來說,設 為最大權重,則
在下圖中,可以看到一張圖有邊權與點權,點權的加總是 ,而最大匹配權重 。不難發現 ,且
若把 的數值減少為 ,那我們依然會則到 ,且
當一張圖並沒有點權時,我們可以自由設計點權,使對於所有 , ,且 。在匈牙利演算法當中,我們會運用到這個性質
Egerváry 定理是 Kőnig 定理的拓展。簡單來說,Jenő Egerváry 引入了權重的概念到 Kőnig 定理當中,因此這兩定理又被稱為 Kőnig-Egerváry 定理
Egerváry 定理必須符合三個條件:
對於一張帶邊權的二分圖,若其邊權不為負,且存在一個匹配 使所有點都被匹配到 (即完美匹配),則最小權點覆蓋問題等價於最大權匹配問題
換句話說,有一帶權點覆蓋 若且為若 包含了邊 使 ,在此情況下有最佳解
一張有權二分圖的等效子圖 是 的生成圖 (即包含所有節點的圖),其所有邊皆符合 。只要我們調整點權,就會產生不同的等效子圖
右圖為左圖的等效子圖
有了以上材料,我們可以來說明匈牙利演算法到底如何運行
根據 Egerváry 定理的描述,其實整個演算法要達到的目標僅有兩個:
要達成這些目標,我們需要不斷的調整權重,直到
先定義一個名詞 excess,是指對於 ,
令 為一個點覆蓋,使 、
找出等效子圖 中的最大匹配 。若 是一個完美匹配,則停止迭代,並回傳 為最大權完美匹配。否則,令 是在 中大小為 的點覆蓋,再令 、,又令最小 excess 為 。將 中的 減去 ,且 中的 加上 ,然後再次迭代
其中,尋找最大匹配 的演算法,可以使用擴充路徑演算法。從另一角度來看,擴充路徑演算法算是匈牙利演算法的子程式
註 : 這邊以下所使用的 為節點, 分別為節點 的點權
首先,將 設為 。為了要符合 ,我們必須挑選相鄰節點 最大邊權的邊。換句話說,就是設
我們可以觀察下圖其中一個節點 為什麼要選擇 ,而不是 。因為選擇 ,才會符合
接下來下一個步驟,我們需要去找出等效子圖 。並找出等效子圖中的最大匹配 。會發現右圖的最大基數匹配小於 ,因此不是最大權匹配,在這種情況需要繼續迭代
我們可以找出大小為 的獨立集 ,其中 、。由此可以找出 、,因此算出 。我們將 的點權減去 、 的點權加上 ,得到下左圖的新權重,以及右圖的新等效子圖與新的匹配。由於此時的匹配並不是完美匹配,我們繼續迭代
可以注意的是,此時的 ,而
我們可以再找出大小為 的獨立集 ,其中 、。由此可以找出 、,因此算出 。我們將 的點權減去 、 的點權加上 ,得到下左圖的新權重,以及右圖的新等效子圖與新的匹配
可以注意到,此時 。根據 Egerváry 定理,我們已經找到了最大權完美匹配,因此可以停止迭代並回傳答案
實作主要可以分為原始的 版跟優化過的 版
然後又依走訪方法不同分為 DFS 與 BFS 兩種版本
我兩種都放,這樣比較有趣一點
這版本是原本尚未經過優化的版本
在實作上,我們可以定義一個 的鬆弛量 slack,即為程式碼中的 ,且每次開始找擴充路時初始化為無窮大,這樣才能找到最小值。在尋找擴充路的過程中,檢查邊 時,如果它不在等效子圖中,則讓 變成原值與 的較小值。如此一來, 節點的 slack 值中的最小值作為 值即可
需要注意的是,在運算時, 的節點 slack 值都要減去
總時間複雜度:
位於修改 後的地方增加了一個迴圈,用於判斷該次的修改是否產生可行的擴充路徑。對於新增加的 的邊,若他有機會是擴充路徑的話,會對此邊連向的節點 進行 BFS 判斷有沒有擴充路徑
總時間複雜度:
因為用圖來看實在太麻煩了,所以我們可以用 矩陣來處理匈牙利演算法
註 : 因為中文太複雜了我總是分不清列與行,因此我就用 row 與 column 來說明,以防自己寫錯
如上面例子,我們再來處理一次這張二分圖,但這次使用矩陣來處理
如上圖,我們可以得到以下鄰接矩陣,裡面每一個元素都表示邊權
我們可以定義一個 excess 矩陣 ,將每 row 都減去其中的最大值,使每一個元素皆為 。此時,、
如果將 excess 矩陣對照等效子圖 ,會發現一組匹配會對應到一個 的集合,使此集合沒有兩個 共用同一個 row 或 colum,下圖以底線表示匹配邊。建議可以畫一條直線或橫線覆蓋行或列來確認之
畫直線與橫線最少的線條覆蓋所有的 之後,會發現直線對應 、橫線對應
此時 、
接下來,藉由直接對照 , 很快就能找出 。我們將 減去 , 加上 ,便會得到以下矩陣。藉由這個矩陣,我們可以試著用最少的線覆蓋所有 的邊權,並找出 與
注意此時的 、
接下來,對 再找一次最小 excess,找出 。我們將 減去 , 加上 ,便會得到以下矩陣。藉由這個矩陣,我們可以試著用最少的線覆蓋所有 的邊權,並找出 與
注意此時的 、
到此會發現,已經找到一組 ,使 ,這就代表已經找到一組最大權完美匹配 (即畫底線的邊),因此我們停止迭代並回傳答案
註 : 如果在網路上搜尋,會發現另一種矩陣的執行方法。另一種方法是先將每 row 的最小值扣除,再將沒有 的 column 扣除最小值,接下來再執行減去 的步驟。然而,另一種方法並沒有辦法處理 有未連邊,也就是邊權為 的情況,也就是網路上的方法只能解決二分圖是 -regular 的狀況,且邊權大於 的情況。因此,使用本文上述方法才是正確的通用解法
題目來源: Codeforces 1107 F. Vasya and Endless Credits
這題根本閱讀題
有人想要不勞而獲買一台車,已知銀行有 個貸款方案,每個貸款方案會在一開始給一筆錢 ,然後接下來 個月都要扣 元。然而,這個人可以在存到錢買到車之後就開車烙跑,問說買車的錢最多是多少
每一個方案只能使用一次
每個月最多只能最多申請一個方案
根據題目,最多只會有 個月,因此找 個方案與 個月的最大權完美匹配就好了,邊權就是的定義如下面程式碼
加負號在每一條邊的邊權,即可反轉大小關係。雖然這樣看似違反 Egerváry 定理的限制,但其實很多人寫的程式實作不會因此受影響。如果會影響的話,就抓個最大值來減去所有邊權,這樣依樣可以轉化成可以解的問題
在大小為 的獨立集補上點與權重為 的邊,使 。如果要求最大權,則將負權邊設為
匈牙利演算法是由美國數學家 Harold Kuhn 在 1955 年提出 (參見原文: The Hungarian method for the assignment problem),會取名「匈牙利」是為了紀念兩位匈牙利數學家 Dénes Kőnig 與 Jenő Egerváry,也就是提出 Kőnig-Egerváry 定理的那兩位數學家,因為這個演算法有很多內容都是基於那兩位匈牙利數學家的貢獻
其中,Dénes Kőnig 曾寫出第一本圖論的書,英譯為 Theory of finite and infinite graphs (書裡面很多表示方法都不是現代圖論會用的,而且圖偏少,沒事不要讀),可說是現代圖論領域的開山祖之一
在 1957 年數學家 James Munkres (就是寫出那本很經典的 Topology 的那位),證出匈牙利演算法是 ,因此此演算法又被稱為 Kuhn-Munkres 演算法。在之後又有人將演算法優化到
從某些角度看來,擴充路徑演算法只是匈牙利演算法的子程式,有許多資料 (中文居多) 會錯誤地將擴充路徑演算法講成匈牙利演算法
OnlineJudge 11383 - Golden Tiger Claw (匈牙利演算法觀念裸題)
OnlineJudge 1045 - The Great Wall Game
OnlineJudge 10746 - Crime Wave - The Sequel
OnlineJudge 10888 - Warehouse
ShanC 程式競賽筆記
作者: ShanC
更新: 2025/2/5