这篇博客介绍了匈牙利算法的操作步骤,不讨论原理。
作用
解决指派问题。所谓的指派问题就比如:甲乙丙三个人去做ABC三件事情。每个人做每件事情所花的时间可能不一样。每个人只能安排一件事情,问怎样安排才能使三个人所工作的时间之和最小?
扩展成 n 个人 n 件事也可以,但要求是:
- 事情数和人数一样多
- 每人只能做一件事
这样的问题就称作指派问题
匈牙利算法就是解决这样的问题的。
实例
甲乙丙中第i (i=1,2,3)
个人做ABC中第j (j=1,2,3)
件事的时间为 Aij。矩阵 A 如下
2 3 4
3 4 6
5 6 1
就是说甲做A事情要2分钟,做B事情要3分钟; 乙做C事情要6分钟,以此类推。问怎样安排才能使甲乙丙三人所用的时间最少?
下面用匈牙利算法来解。
算法目标
让矩阵中出现 n 个满足不同行不同列的 0。 上述问题就是要3个不同行不同列的0.
步骤概括
- 每行减去此行最小数
- 判断是否达到算法目标,如未达到算法目标,继续下一步。否则结束。
- 横纵交替,从行开始。找出所有还没有选中
0
的行(具体见步骤实例),在此行后面打钩; 把此行中有0
的列全打钩。在打钩的列中,如果有零,又在有0
的行打钩,如此交替,直到不能再打钩。 - 在没有打钩的行和打钩的列上划线,会得到发现所有的
0
已经被划去,如果没有划去,请检查前面的步骤。此时剩下的所有元素中,找到最小值,就记为min
吧。 - 在第4步画线的行减去
min
(此时原来的0
变成-min
),再在画线的列加上min
(此时矩阵中没有了负数)。回到第 2 步。
步骤实例
对于之前的矩阵
2 3 4
3 4 6
5 6 1
- 每行减去此行最小值,由(1)变成(2),如图:
2. 检查发现没有达到算法目标,因为(2)中只有两个不同行不同列的0
,图中红色的0
。没有达到算法目标。
3. 找出没有选中0
的行,在后面画勾,如图(3)。
此行的0
在第1列,在第 1 列画勾,如图(4),发现第 1 列有两个 0,其中第一行的 0 还没有画勾,于是在第 1 行后画勾,如图(5)。此时没有勾可画了,进行下一步。
4. 在没有打钩的行,即第 3 行,和打钩的列,即第 1 列,划线,会得到发现所有的0
已经被划去。然后找出最小值min,此处min = 1
。如图(6)
5. 在第4步未画线的行减去min
,即在第1、2行减去 1,结果如图(7)。再在画线的列加上min
,即在第 1 列加上 1,结果如图(8)。
6. 判断发现(8)满足算法目标,当然也有图(9)满足算法目标。
最后一公里
如图(8),第1、2、3行的 0 分别在相应行的第 1 、2、3个,所以第 1 个人做第 1 件事,第 2 个人做第 2 件事,第 3 个人做第 3 件事。
图(9)对应的是第 1 个人做第 2 件事,第 2 个人做第 1 件事,第 3 个人做第 3 件事。
带入图(1)计算可以知图(8)和图(9)所用的时间相同,都是(2+4+1 = 7)或 (3+3+1 = 7)分钟。
我们把图(8)和图(9)的结果分别写成
1 2 3
1 2 3
1 2 3
2 1 3
总结
要想最快掌握匈牙利算法,就在看完我这篇博客后自己默写一篇。我就是这样做的,现在感觉很好。教别人是一种很好的学习方式,没人教就自己写写博客分享喽!你也可以自己算一个例子试试,其实我已经帮你想好了:对于下面的矩阵,求最少工作量。(希望在你的手机或电脑屏幕上也能看到的矩阵排列得整齐,美感总是很重要的)
5 7 11 5 7
4 8 3 2 2
5 4 6 10 7
10 12 11 10 10
3 7 8 4 5
我得出的结果如下,也未必对,我没有检查:
1 2 3 4 5
4 5 2 3 1
文中若有不足之处,欢迎指正。