许多的算法都用到了匈牙利算法与卡尔曼滤波。今天仔细学习下匈牙利算法以及卡尔曼滤波,匈牙利算法在运筹学课程有所涉及。著名的SORT跟踪算法就是基于匈牙利算法和卡尔曼滤波提出的算法。
匈牙利算法
简介
匈牙利算法是一种求解任务分配问题的组合优化算法,最容易理解的应该是其矩阵解释。
矩阵解释
现假设有n个工人和任务,以及一个分配给每个工人对应任务的成本矩阵 A ( n × n ) A_{(n \times n)} A(n×n)。
现假设
n
=
4
n = 4
n=4,此时把矩阵
A
A
A 表达出来就是;
A
=
(
a
1
a
2
a
3
a
4
b
1
b
2
b
3
b
4
c
1
c
2
c
3
c
4
d
1
d
2
d
3
d
4
)
A = \begin{pmatrix} a_1 & a_2 & a_3 & a_4 \\ b_1 & b_2 & b_3 & b_4 \\ c_1 & c_2 & c_3 & c_4 \\ d_1 & d_2 & d_3 & d_4 \end{pmatrix}
A=⎝⎜⎜⎛a1b1c1d1a2b2c2d2a3b3c3d3a4b4c4d4⎠⎟⎟⎞
其中,
a
i
a_i
ai 代表工人
a
a
a 执行第
i
i
i 个任务的成本,
i
=
1
,
2
,
3
,
4
i=1,2,3,4
i=1,2,3,4 .其他类似。由于A是一个方阵,代表一个工人智能执行一个任务。
step 1 行操作
对于第一行,找出最小的
a
i
a_i
ai ,并且将第一行每个元素减去最小的
a
i
a_i
ai ,此时该行至少有一个元素为0(考虑可能有相同的最小值)。对其他行也如此处理,得到一个每行至少有一个0元素的新的矩阵
B
B
B :
B
=
(
a
1
′
0
a
3
′
a
4
′
0
b
2
′
b
3
′
b
4
′
c
1
′
c
2
′
c
3
′
0
d
1
′
d
2
′
0
d
4
′
)
B = \begin{pmatrix} a_1' & 0 & a_3' & a_4' \\ 0 & b_2' & b_3' & b_4' \\ c_1' & c_2' & c_3' & 0 \\ d_1' & d_2' & 0 & d_4' \end{pmatrix}
B=⎝⎜⎜⎛a1′0c1′d1′0b2′c2′d2′a3′b3′c3′0a4′b4′0d4′⎠⎟⎟⎞
此时每行每列各有一个0元素,即可指派任务,且此时的成本最小,任务指派方案为:
(
a
,
2
)
,
(
b
,
1
)
,
(
c
,
4
)
,
(
d
,
3
)
(a,2),(b,1),(c,4),(d,3)
(a,2),(b,1),(c,4),(d,3)
step 2 列操作
若step 1 所得矩阵不能满足每行每列一个0元素,例如;
C
=
(
a
1
′
0
a
3
′
a
4
′
0
b
2
′
b
3
′
b
4
′
c
1
′
c
2
′
c
3
′
0
0
d
2
′
d
3
′
d
4
′
)
C = \begin{pmatrix} a_1' & 0 & a_3' & a_4' \\ 0 & b_2' & b_3' & b_4' \\ c_1' & c_2' & c_3' & 0 \\ 0 & d_2' & d_3' & d_4' \end{pmatrix}
C=⎝⎜⎜⎛a1′0c1′00b2′c2′d2′a3′b3′c3′d3′a4′b4′0d4′⎠⎟⎟⎞
此时不能作出指派,因为任务1 适合工人b和d,但没有工人适合做任务3 ,此时怎么办?
此时对所有列类比step 1 执行减去每列最小元素的操作,此时大多数情况都可以指派任务。
如:假设
C
C
C中第三列b元素最小,则有
D
=
(
a
1
′
0
a
3
′
a
4
′
0
b
2
′
0
b
4
′
c
1
′
c
2
′
c
3
′
0
0
d
2
′
d
3
′
d
4
′
)
D = \begin{pmatrix} a_1' & 0 & a_3' & a_4' \\ 0 & b_2' & 0 & b_4' \\ c_1' & c_2' & c_3' & 0 \\ 0 & d_2' & d_3' & d_4' \end{pmatrix}
D=⎝⎜⎜⎛a1′0c1′00b2′c2′d2′a3′0c3′d3′a4′b4′0d4′⎠⎟⎟⎞
若仍不可以,进行step 3 。
step 3
我们想用尽可能少的行或列标记覆盖矩阵中的所有零。就矩阵 C C C而言,显然只用三条直线就能够覆盖矩阵中所有的“0”元素。
当覆盖“0”元素的直线小于效率矩阵的阶数时,我们需要从行和列结合的角度,产生等价的效率矩阵,有更多的“0”元素。
现假设得到效率矩阵:
E
=
(
a
1
′
0
a
3
′
a
4
′
0
b
2
′
b
3
′
b
4
′
c
1
′
c
2
′
0
0
0
d
2
′
d
3
′
d
4
′
)
E = \begin{pmatrix} a_1' & 0 & \color{red} {a_3'} & \color{red} {a_4'} \\ 0 & b_2' & \color{red} {b_3'} &\color{red} {b_4'} \\ \color{green} c_1' & \color{green} c_2' & 0 & 0 \\ 0 & d_2' & \color{red} {d_3'} & \color{red} {d_4'} \end{pmatrix}
E=⎝⎜⎜⎛a1′0c1′00b2′c2′d2′a3′b3′0d3′a4′b4′0d4′⎠⎟⎟⎞
显然三条直线即可覆盖全部零元素,此时行列最小值皆为0,不能通过step 1 和step 2进行变换,
此时,找出未覆盖元素中的最小值,,对未覆盖元素减去最小值,直线交叉处元素加上最小值,其余不变。
对于矩阵
E
E
E来说,未被覆盖的红色元素减去其中最小的,交叉的绿色元素,加上减去的最小值。不妨设为
d
3
′
d_3'
d3′,于是得矩阵:
F
=
(
a
1
′
0
a
3
′
′
a
4
′
′
0
b
2
′
b
3
′
′
b
4
′
′
c
1
′
′
c
2
′
′
0
0
0
d
2
′
0
d
4
′
′
)
F = \begin{pmatrix} a_1' & 0 & \color{red} {a_3''} & \color{red} {a_4''} \\ 0 & b_2' & \color{red} {b_3''} &\color{red} {b_4''} \\ \color{green} c_1'' & \color{green} c_2'' & 0 & 0 \\ 0 & d_2' & \color{red} {0} & \color{red} {d_4''} \end{pmatrix}
F=⎝⎜⎜⎛a1′0c1′′00b2′c2′′d2′a3′′b3′′00a4′′b4′′0d4′′⎠⎟⎟⎞
此时,四条直线完全覆盖所有零元素,可以分配:
(a,2),(b,1),(c,4)(d,3)。
当然上述情形可能并不完整,比如就没有讨论零元素形成闭回路的情况。
两个定理
以上计算方法是建立在数学家克尼格(Konig)证明的两个定理的基础上。
- 如果从分配问题的效率矩阵 A i j A_{ij} Aij的每一行元素中分别减去(加上)一个常数 u i u_i ui(该行位势),每一列元素分别减去(加上)一个常数 v j v_j vj(该列位势),得到一个新的效率矩阵 B i j B_{ij} Bij,若其中 b i j = a i j − u i − v j b_{ij} = a_{ij} - u_i - v_j bij=aij−ui−vj,则 B i j B_{ij} Bij的最优解等价于 A i j A_{ij} Aij的最优解。
- 若矩阵 A A A的元素可以分为“0”与非“0”两部分,则覆盖“0”元素的最少直线数等于位于不同行不同列的“0”元素的最大个数。
数学上的矩阵形式很容易就理解了,至于二分图形式,有许多资料详细解释了二分图的匹配过程,不赘述。
二分图形式文章推荐
贴一篇写的不错的:匈牙利算法二分图表示及代码
可以仔细食用。