通常图最大匹配——带花树

所谓花,就是以下图所示的一个奇环: 1算法

本文中粗边表明如今的匹配边,细边表明该点的前驱(后文会讲解前驱是什么,如今只须要知道每一个点和它的前驱在原图中必定是有边的)。blog

如图所示,一朵包含$2k+1$个点的花必定至多包含$k$条匹配边,因而总会剩下一个未匹配的点,上图中即为$1$号点。队列

那么咱们能够发现,若是有另一个点想要与花中的某个点$v$匹配,那么有两种状况:一、$v$是未匹配的点(即1号点),那么直接与$v$匹配便可。二、$v$是已经匹配的点,这时只要将花中的匹配情况修改,使得$v$变成未匹配的那个点便可。class

综上所述,只要花中的点没有向外匹配,咱们老是可使得外部的一个点和花中任意一个点匹配,所以花的性质和点其实很类似。咱们将花缩成一个点来处理,就能够解决出现奇环的问题。以上思想就是带花树算法的核心。扩展

==================总之分割一下好了==================im

带花树算法的过程其实和$bfs$版本的匈牙利是很类似的,都是找出一个交错树,交错树可能长这样(注意每一个蓝色点可能有多个橙色儿子,可是每一个橙色点只能有一个蓝色儿子): 2img

其中1号点就是咱们尝试增广的节点,在这里咱们给每个节点一个$type$值,若该点不在交错树中,它的$type$值为$0$,不然为$1$或$2$。上图中咱们用蓝色点表明$type=1$的点,橙色点表明$type=2$的点,不难看出$type$值的不一样其实表明了一种相似于二分图的关系,每一个点在交错树中只和$type$值不一样的点相连。当咱们没有找到奇环的时候,$type$值和二分图是等价的。di

那么仿照匈牙利的过程,咱们将尝试增广的点$v$的$type$值设为$1$并开始增广,假设当前处理的点为$u$:思考

一、若是$type_u=0$,就表明它不在交错树中:co

当$u$已经有匹配时,咱们就扩展这棵交错树,将$type_u$的值设为$2$(由于其和$type$值为$1$的$v$相邻),并将$type_{match_u}$的值设为$1$(同理)。这时咱们就能够把$match_u$塞进队列里了,若是可以沿着$match_u$找到增广路的话咱们就可让$match_u$匹配那个增广的点并将$u$与$v$匹配,这样就使匹配数增长了$1$。同时咱们将$u$的前驱(用$pre_u$表示)设置为$v$,这是为了方便在找到增广路之后一路返回修改匹配。

当$u$并无匹配时,咱们就成功找到了一条增广路,此时沿着由$pre$和$match$连成的边一路修改就增广完成了,返回。

二、若是$type_u=2$,表明你找到了一个偶环,并无什么用,就跳过这个点。

三、这里是最重点的,若是$type_u=1$,表明你找到了一个奇环,这就表明你的$type$值再也不等价于二分图了,咱们这个时候就能够开始“缩花”操做,将咱们找到的奇环缩成一个点。让咱们具体的考虑一下:

首先,快速找到哪些点在这个奇环中,显然$u$和$v$必定都出如今交错树上($type$不为$0$),结合上面的那张图考虑,奇环的范围就是两个点在交错树上的链中包含的全部点,所以咱们须要找到这两个点的$lca$,这里直接采用暴力向上跳的作法便可。

找到之后怎么链接$pre$边呢?咱们参考一下文章开头的结构,能够发现此时的$lca$必定就是那个花中惟一的没有匹配或者匹配到外面节点的$1$号点。所以感性思考一下,咱们应该“诱导”其余全部的点经过$pre$和$match$边一路走走到$lca$上,所以将除了与$lca$相连的$pre$边外其余的$pre$边都改成双向边,并将$u$和$v$也改为双向边便可达到这个目的。

最后作一点扫尾工做,咱们能够经过并查集将奇环缩成一个点(所以在普通增广的时候也要考虑并查集的状况),不妨用$lca$作这朵花的表明。同时再考虑一下这个新点的$type$值应该设为何,由于每一个橙色点最多只有一个儿子(它的匹配点),所以$lca$必定是蓝色点,所以新点的$type$值为$1$,因此要注意将花中全部$type$值为$2$的点修改成$1$而且加入队列。

当咱们找不到新的点时,本次增广失败。

===============分割分割================

以上就是通常图最大匹配的增广过程,注意在每次增广以前,$pre$,$type$以及并查集都是要初始化的。将并查集的复杂度看做常数,则每次增广至可能是$O(m)$的,一共须要增广$O(n)$次,所以带花树算法的复杂度和匈牙利同样,都是$O(nm)$,固然,在实践中带花树算法跑得通常会比理论上界快不少。

相信在熟练理解带花树的过程后必定能写出代码,所以为了避免对读者形成思惟定式影响这里就不贴代码了。完结撒花~

相关文章
相关标签/搜索