许多的算法都用到了匈牙利算法与卡尔曼滤波。今天仔细学习下匈牙利算法以及卡尔曼滤波,匈牙利算法在运筹学课程有所涉及。著名的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)证明的两个定理的基础上。
数学上的矩阵形式很容易就理解了,至于二分图形式,有许多资料详细解释了二分图的匹配过程,不赘述。
贴一篇写的不错的:匈牙利算法二分图表示及代码
可以仔细食用。