匈牙利方法是一种可以在多项式时间内解决分配问题(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
对上个测试用例计算最大代价
综上,相较于方法一,方法二可以处理各类情况。