Kuhn Munkres 算法入门
之前做一道 KM 题,被卡 DFS 了。现在来填坑,学一个 BFS 版。
KM 算法通过维护结点的顶标来求出二分图的最大权完美匹配,其正确性可以由对偶定理证明。
对于个点左右两边点数相同的二分图,KM 算法的复杂度是的。
完美匹配:每个点都是某个匹配边的端点的匹配。
最大权匹配转化为最大权完美匹配:对于左右点集大小不相同的二分图,我们可以把点集小的补满,新增一些权值为的边,这不会影响答案。
对于结点,记其顶标为,可以理解为点权。记边权为。
KM 算法将在始终保证的情况下最小化,并给出匹配的方案。根据对偶定理,最小化的记为最大匹配的权值。
相等子图
KM 算法执行过程中会维护一个子图,其中维护的是满足的边。
为什么维护相等子图
根据对偶定理,保证的情况下最小化得到的是最大权匹配。不妨设这个匹配是,那么对于一定有。两边对求和,发现是相等的,因此一定有。
换言之,只要存在使得相等子图有完美匹配,那么我们就找到了最大权匹配。
注意,完美匹配是与权值无关的。这个概念是基于不带权二分图的。在理解 KM 算法的过程中不要与带权匹配混淆。
因此我们有了一个 KM 算法的雏形:
- 在相等子图里増广。
- 如果増广不了,就改一改顶标。
重复上述步骤直到找到完美匹配。当然,因为,所以完美匹配是一定存在的。
KM 算法
直接给出 KM 算法的框架。
初始化:
- 对于,让。
- 对于,让。
DFS 版的比较好懂,但是难写而且跑得慢,这里我们讲 BFS 版。
我们依次枚举右部的点来作为増广结束的位置。
然后 BFS:
- 对于右部的点,我们枚举相等子图中与它相邻的点继续搜索;
- 对于左部的点,我们直接跳到与它匹配的点上去。如果没有与它匹配的点,那么我们就找到了増广路。
在 BFS 的过程中记录前驱指针。増广的时候倒着増广。也就是说是从左部的未匹配的点増广到右部的未匹配点()。
如果増广失败,就考虑调整顶标值。
顶标的调整方式与増广的方向有关。如果是从左到右増广,那么就以左加右减的方式;反之亦然。
左加右减:将左部 BFS 树上的点的顶标统一增加,将右部 BFS 树上的点的顶标统一减少。
设 BFS 树的点集是。
在这样操作之后:
- 相等子图里的边依然满足。
- 对于的边仍不属于相等子图。
- 对于的边,它原来不属于相等子图,现在可能进入了相等子图,因而使相等子图得到了扩大。
根本原因
我们的増广路实际上是从 BFS 树的叶子走到根()。我们应当扩展 BFS 的叶子而不是给 BFS 树的根结点加一个父节点。前者对应的边,后者对应的边。
那么考虑的值。为了保证对每条边成立,则有
实际上我们可以对左部点维护一个松弛变量,这样就有。而可以在 BFS 的过程中维护。
在做完了左加右减之后,至少有一条的边会加入相等子图,即一定会有増广路。因此我们再进行一轮増广即可。
修订记录
- 2021年4月2日 第3次修订
- 2021年1月19日 第2次修订
- 2021年1月18日 创建文章