使用匈牙利算法求解任务分配问题

匈牙利算法(The Hungarian Algorithm)是一种在多项式时间内求解任务分配问题的组合优化算法。

关于任务分配问题,可以参考维基百科上的一个例子:

你有三个工人:吉姆,史提夫和艾伦。 你需要其中一个清洁浴室,另一个打扫地板,第三个洗窗,但他们每个人对各项任务要求不同数目数量的钱。 以最低成本的分配工作的方式是什么? 可以用工人做工的成本矩阵来表示该问题。例如:

清洁浴室 打扫地板 洗窗
吉姆 $2 $3 $3
史提夫 $3 $2 $3
艾伦 $3 $3 $2

在简单的数据和维度下,我们可以快速确认最优任务分配策略是:

  • 吉姆清洁浴室
  • 史提夫打扫地板
  • 艾伦洗窗

一共花费 $6,这是我们最优的解决方案。

如果数据更加复杂,或者上升到更高的维度,该如何求解呢?使用匈牙利算法就可以快速求解出最优的任务分配方案。

步骤和状态转换,在图中的例子写的非常清楚:

  1. 给出一个 n * n 的矩阵,m[i][j] 表示不同的人对不同的任务所要求的花费
  2. 针对每一行,选出最小值,并给该行的每个元素都减去这个最小值,可以得到一个新的矩阵
  3. 对于新的矩阵,针对每一列,同样选出最小值,并给该列的每个元素都减去这个最小值,可以得到一个新的矩阵
  4. 此时的矩阵中有些元素是 0,画最少的线来覆盖其中的 0,如果线的条数就是矩阵的维度,此时就结束变换了(跳转到第 8 步),否则继续第 5 步
  5. 针对没有画线的行,挑出所有行中值最小的元素(不是每一行,是所有行),然后针对行元素做减法,得到新矩阵
  6. 针对画线的列,由于原来有 0,做减法后会出现负值,此时需要把刚刚减去的值给加回来,得到新矩阵
  7. 继续画线,直到线的条数与矩阵的维度一致(不一致,则跳转到第 5 步)
  8. 对于每一行,先找到只有一个 0 的行,然后删除 0 元素对应的列上其他的 0,重复,直到所有行都选出了 0
  9. 对于筛选出来的 0 元素,其对应的坐标映射到原始矩阵,就是我们的最优任务分配方案

References: