匈牙利方法是一種可以在多項式時間內解決分配問題(assignment problem)的組合優化算法。它由Harold Kuhn 與1955年發展並提出,因爲該算法很大程度上依賴於先前兩位匈牙利數學家:Denes Konig 和 Jeno Egervary,因此被命名爲「匈牙利方法」。
1957年James Munkres從新審視了這個方法,證實發現該方法是嚴格polynomial的,因此以後該方法也被稱爲Kuhn-Munkres 算法或者Munkres分配算法。原始的匈牙利算法的時間複雜度是,然而以後Edmonds和Karp,以及Tomizawa獨立發現通過必定的修改,該算法能改達到
的時間複雜度。 Ford和Fulkerson將該方法擴展到通常運輸問題的求解上。 2006年,研究發現Carl Custav Jacobi在19實際就解決了assignment問題,而且在其逝世後的1890年求解過程被以拉丁語形式發表。。。web
匈牙利法解決的指派問題應該具備兩個約束條件算法
workes 和tasks的數目應該相同,即o2o問題。windows
求解的是最小化問題,如工做時間的最小化、費用的最小化等等數組
指派問題示例:
有三個workers: Jim, Steve和Alan,如今有3個工做:clean the bathroom, sweep the floors和wash the windows須要交給這三我的,每一個人只能完成一個任務,對應的cost matrix以下svg
--- | Clean bathroom | Sweep floors | Wash windows |
---|---|---|---|
Jim | $2 | $3 | $3 |
Steve | $3 | $2 | $3 |
Alan | $3 | $3 | $2 |
那麼如何分配任務是開銷最小就是一個指派問題測試
問題: 假定某單位有甲、乙、丙、丁、戊五個員工,現須要完成A、B、C、D、E五項任務,每一個員工完成某項任務的時間以下圖所示,應該如何分配任務,才能保證完成任務所須要的時間開銷最小?優化
解:ui
寫出係數矩陣spa
更新系數矩陣,使係數矩陣的每一行每一列都減去該行該列的最小值,保證每一行每一列都有0元素出現,參見定理2.3d
選擇只有一個0元素的行或列將該0元素標註爲獨立0元素,並將該0元素所在的列或行中0元素劃掉,直至找不到知足條件的行或列,須要注意的是在循環時,劃掉的0元素再也不視爲0元素。好比咱們找下面這個係數矩陣的標註0元素和劃掉的0元素
那麼咱們用1表示0元素,0表示非0元素,用2標註獨立0元素,-2表示劃掉0元素,依次獲得的中間結果爲
能夠發現咱們在標註第一行第2個0元素時,並無把已經劃掉的第一個0看成0元素看待。
劃蓋0線。
a. 首先找到不含有獨立0元素的行,將行標註 (4)
b. 找到標註行中劃掉的0元素所在的列,將列標註 (2,3)
c. 將標註列中獨立0元素所在的行標註 (4, 1, 2)
d. 重複b,c步驟知道全部的標註行中再也不存在劃掉的0元素
(行:4 ,1, 2, 3 ; 列: 2, 3, 1)
e. 在全部標註的列上作蓋0線,在全部未被標註的行上作蓋0線,咱們在矩陣中用3表示被蓋0線覆蓋,則
能夠發現全部的0元素都被覆蓋掉,因此稱爲蓋0線。
根據定理1,若是此時蓋0線的個數等於矩陣的維數,至關於找到n個獨立0元素,則跳到步驟7,不然步驟5更新系數矩陣。
更新系數矩陣。
a. 找到未被蓋0線覆蓋的元素中的最小值
b. 全部未被蓋0線覆蓋的元素減去最小值
c. 全部蓋0線交叉處的元素值加上最小值
重複步驟4,5
計算最優解。
相似步驟3中找獨立0元素的方法在C中找到n個不一樣行不一樣列的0元素所對應的位置。
定理1. 係數矩陣C中獨立零元素的最多個數等於能覆蓋全部零元素的最少線數。 —— D. Konig
定理2. 若將分配問題的係數矩陣每一行及每一列分別減去各行及各列的最小元素,則新的分配問題與原分配問題有相同的最優解,只是最優值差一個常數。
固然,注意找蓋〇線的方法並非惟一的,好比下述方法
同上一方法
同上一方法
在C中尋找未被蓋〇線覆蓋的存在0元素且數組最少的行(列),標註一個0元素做爲獨立0元素,該0元素所在的列(行)作蓋0線。重複此步驟,直至找不到符合條件的行或列,已經被找過的行(列)就再也不找了!
如果蓋0線數組等於矩陣維度,則跳到7
同上一方法
重複3,4,5
同上一方法
固然還有別的方法,好比從包含最多0元素的行或列開始作蓋0線直到將全部的0元素覆蓋掉等
這裏代碼實現了上面兩個方法,註釋掉的是第二個方法的核心
workers數小於tasks數目
此時能夠虛擬出若干個workers使個數相等,對於虛擬出的workers對於tasks的代價是相同的都是0.
workers數目大於tasks數目
能夠和上述相似,增長虛擬tasks,在係數矩陣中對應列元素都爲0
最大值問題
找到係數矩陣中最大的元素,而後使用最大元素分別減去矩陣中元素,這樣最大化問題就化爲最小化問題,一樣可使用匈牙利算法。
如今使用代碼求解上述例題
注意方法一中存在不足之處是必須找到僅含一個0元素的行或列,這並不科學,好比下面這個係數矩陣,就會出現死循環,因此能夠尋找含有最少0元素的行或列,這就和方法二相似了,因此我沒再實現。方法二能夠解決下面這個極端例子
咱們來使用方法二(將代碼中註釋掉的部分反註釋,方法一註釋掉)測試下這個極端的例子
測試下面這個係數矩陣,匈牙利算法拓展1
對上個測試用例計算最大代價
綜上,相較於方法一,方法二可以處理各類情況。