Hungarian算法步骤

匈牙利算法步骤

作用

解决指派问题。所谓的指派问题就比如:甲乙丙三个人去做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.

步骤概括

  1. 每行减去此行最小数
  2. 判断是否达到算法目标,如未达到算法目标,继续下一步,否则结束.
  3. 横纵交替,从行开始.找出所有还没有选中0的行,在此行后面打钩;把此行中有0的列全打钩.在打钩的列中,如果有零,又在有0的行打钩,如此交替,直到不能再打钩.
  4. 在没有打钩的行和打钩的列上划线,会得到发现所有的0已经被划去,如果没有划去,请检查前面的步骤.此时剩下的所有元素中,找到最小值,就记为min.
  5. 在第四步未画线的行减去min(此时原来的0变成-min),再在画线的列加上min(此时矩阵中没有了负数).回到第二步.

步骤实例

# 0)初始矩阵

2 3 4
3 4 6
5 6 1

# 1)每行减去此行最小值

0 1 2
0 1 3
4 5 0

# 2)检查发现没有达到算法目标
只有两个不同行不同列的0 ,没有达到算法目标

# 3)找出没有选中0的行,在后面打钩 
此行的0在第一列,在第一列画勾;发现第一列有两个0,其中第一行的0还没画勾;于是第一行后画勾.

0 1 2 √
0 1 3 √
4 5 0 
√

# 4)在没有打钩的行,即第三行,和打钩的列,即第一列,划线.会得到发现所有的0已经被划到.然后找到最小值min,此处min=1

|0|  1   2

|0|  1   3        min=1
+-+--------
|4|  5   0
-----------

# 5)在第四步未画线的行减去min,再在画线的列上加min,最后得到

0 0 1
0 0 2
5 5 0

结果可以是

O 0 1                   0 O 1
0 O 2    也可以是        O 0 2
5 5 0                   5 5 0

也就是甲2乙1丙3或者甲1乙2丙3:
带入初始矩阵:
2 3 4
3 4 6
5 6 1

3+3+1 或 2+4+1
最小代价都是7

例子和思路

四个工作(W1,W2,W3和W4)需要执行四个作业(J1,J2,J3和J4)

82 83 69 92
77 37 49 92
11 69  5 86
 8  9 98 23

# 1)减去行最小值

我们首先从每行中减去行最小值。例如,第一行中的最小元素是69.因此,我们从第一行中的每个元素中减去69。得到的矩阵是:

12 14  0 23
40  0 12 55
 6 64  0 81
 0  1 90 15

# 2)减去列最小值

同样,我们从每列中减去列最小值,给出以下矩阵:

13 14  0  8
40  0 12 40
 6 64  0 66
 0  1 90  0

# 3)用最少的行数覆盖全零

我们现在将确定覆盖矩阵中所有零所需的最小行/列数(水平或垂直)。可以使用2行+1列(第二行,第四行,第三列)覆盖所有零:

13 14  0  8
40  0 12 40 X
 6 64  0 66 X
 0  1 90  0
       X
因为所需的行数(3)低于矩阵的大小(n = 4),所以继续步骤4.

# 4)创建其他零

首先,我们发现最小的未覆盖数是6.我们从所有未覆盖的元素中减去这个数字,并将其添加到所有被覆盖两次的元素中。这导致以下矩阵:

 7  8  0  2
40  0 18 40
 0 58  0 60
 0  1 96  0

获得方法可参见上部:
1. 横减
2. 竖加

 7  8  0  2 
40  0 18 40
 0 58  0 60
 0  1 96  0

 最佳匹配 [3,2,1,4]

 69+37+11+23 = 140

 代价最小
updatedupdated2021-02-262021-02-26