【图论】【一般图匹配】带花树算法详解

您所在的位置:网站首页 图论中的树是什么样的 【图论】【一般图匹配】带花树算法详解

【图论】【一般图匹配】带花树算法详解

#【图论】【一般图匹配】带花树算法详解| 来源: 网络整理| 查看: 265

【图论】【一般图匹配】带花树算法详解

Singercoder

2020-04-06 20:27:58

Solution # 算法介绍 + 算法简介:带花树算法,是一种在一般图中寻找最大匹配的算法。它是以匈牙利算法为基础,并特别加入了对奇数环的讨论后形成的。 + 前置知识:**bfs**匈牙利算法+并查集 # 模板分析 直接以[uoj79](http://uoj.ac/problem/79)为模板讲解。luogu数据过水,无法卡掉所有错误做法。 1. 创造性的算法往往是在已有基础上改进形成的,带花树算法亦是如此。 我们考虑在一个一般图中,不存在奇数环,即为一颗存在偶数环的树,可以想到直接对其进行二分图染色+匈牙利算法(二者可以同时进行)解决,这是带花树算法的基础框架。(code省略了部分细节) ```cpp bool bfs(int s) { while(!q.empty()) { u=q.front();q.pop(); for(int v=1;vN),而这条増广路是从花内距花根较远的一条路延伸来的(如图中J->I->H->N)。 3. 考虑如何记录这条较远的非常规路径。我们知道,在匈牙利算法中,对于每一对匹配中的入点v,我们都会有一个pre指向其前驱匹配的出点u(即图中的红色边),也就是说仅有v型点具有pre。 然而在花中,所有点可以作为u型点向外遍历,也就没有了严格的u、v区分。因此无论u、v染色情况如何,我们为花中所有匹配对之间建立相互的pre,具体实现见下(注意由于原本已有部分pre,即红色边,我们要根据特殊性质去建立剩余的pre,即蓝色边)。 特别注意,如果到了u为根节点,就不要再反向建立pre了,因为它所在匹配对并不完全属于花! 这样,无论以哪个点作为u向环外遍历,我们在花内部都能得到正确的増广路。(想一想,以图中表示出的白色点和绿色点分别为起点,向花外遍历,其在花内体现出的増广路分别是什么样的?) ```cpp else//环 { if(get_fa(u)==get_fa(v))continue;//该环已被缩成一点,不必处理 if(col[v]==1)//奇数环,需要将花缩成花根一点 { //此时的u、v均为出点,不适用命名原则 int r=lca(u,v);//寻找lca,即总花根 shrink(u,v,r);//分别从两个方向,建立反向pre,保证花内部増广路正确性 shrink(v,u,r); } //偶数环不必处理 } ``` 3. 你可能会注意到上面的程序框架中出现了lca和shrink这两个函数。 关于lca,我们只要朴素寻找总花根即可,因为遍历的起点总是在变的,无法用倍增lca来加速。 关于shrink,思想就是上述对于花内増广路的维护,也就是建立反向pre。 连带修改増广路的aug函数一起,code如下: ```cpp void aug(int v)//从v点开始修改増广路 { int t; while(v) { t=match[pre[v]];//临时记录下一次的v match[v]=pre[v]; match[pre[v]]=v; v=t; } } int cnt,vis[MAXN]; int lca(int u,int v)//寻找两个节点的总花根 { ++cnt;//每次lca选用不同的cnt作为判断条件 u=get_fa(u);//保证操作对象时刻为分花根 v=get_fa(v); while(vis[u]!=cnt)//某一点同时两次被染色,即为总花根 { vis[u]=cnt; u=get_fa(pre[match[u]]);//保证操作对象时刻为分花根 if(v)swap(u,v);//切换操作对象 } return u; } void shrink(int u,int v,int r)//以r为总花根,将花缩成花根一点,并建立内部的反向pre { while(get_fa(u)!=r)//当已达到总花根,说明缩花任务完成 { //每次循环起初的v为上个匹配的v pre[u]=v;//建立反向pre,保证増广路 v=match[u]; if(col[v]==2){col[v]=1;q.push(v);}//花内所有v,都应以u身份向外増广 if(get_fa(u)==u)fa[u]=r;//如果某一点为分花根,将其合并到总花根上 if(get_fa(v)==v)fa[v]=r; u=pre[v];//切换操作对象 } } ``` 于是基础的匈牙利算法和对奇数环的讨论全部完成,带花树算法成功得到实现。 # 时间复杂度 + 同匈牙利算法,O($n^3$)。 不过常数肯定略大,且编程难度也大幅上升。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3