[转]带花树,Edmonds's matching algorithm,一般图最大匹配
看了两篇博客,觉得写得不错,便收藏之。。
首先是第一篇,转自某Final牛
带花树……其实这个算法很容易理解,但是实现起来非常奇葩(至少对我而言)。
比如昨晚找到一篇鄙视带花树的论文,然后介绍了一种O(E)的一般图最大匹配……我以为找到了神论文,然后ACM_DIY众神纷纷表示这个是错的……于是神论文成为了”神论文“……
又比如围观nocow上带花树标程,一看……这显然是裸的匈牙利算法……货不对板啊
当然……如果二分图的匈牙利算法还不会请先围观求二分图最大匹配的匈牙利算法。
实际上任意图求最大匹配也是找增广路,但是由于奇环的出现,找增广路变得困难。
首先明确一点,增广路上是不能有重复出现的点的。
二分图中,匹配边可以看作是有向的,比如定义总是从X集指向Y集。假若定义了起点必须在X集中,那么增广路中出现该匹配边时,必然是按照这个方向的。所以一个点在增广路中的奇偶性是确定的。
而这个图中,从增广路3->1->4->5和2->4->1->6可以看出,对于有奇环的任意图,1和4这两个点在增广路中所在位置的奇偶性不再一定。于是我们考虑处理这些奇环。
定义奇环:包含2k+1个点和k条匹配边的一个环。(如果不是这样,我们找增广路不会走上去)
对于这个奇环,k条匹配覆盖了2k个点,那么显然有一个点未被覆盖。我们拿出这个点来讨论。
比如图中的1号点就是这个这个特殊的点。除了这个点以外,其它的点都被覆盖了,所以只能向外连非匹配边,而1号点可以向外连匹配边
或非匹配边。
如果1号点没有被外面的点匹配,那么无论从其它的哪个点走进来,都能以1为终点找到增广路。(要么顺时针跑到1,要么逆时针)
同理如果1号点被外面的点匹配了,那么无论从其它的哪个点走进来,都能把这个圈看成一个点,然后从1的那条匹配边穿出去。(要么顺时针,要么逆时针)
于是这个奇环就可以看成一个点,其主要特性由1号点体现(诸如和谁匹配了之流)。
这个合成点就叫做花。这个算法的思想就是不断地把奇环合成点,直至找到增广路(合成了某朵花以后就把整朵花当成一个点)。
考虑用BFS搜索增广路。
围观wiki这个图
由于BFS的性质,我们找到奇环只能是和同层的点,或者下下一层的点。
然后奇环的关键点必然是这棵BFS树里深度最浅的点。然后考虑合成以后,花如何展开对应的路径,使得我们能够增广。
花套花这个东西想起来都纠结>_<。
amber的程序里面并没有把点真的合成,只是弄了一个表示集合的标号:Base,然后邻接矩阵就不用变来变去了。
对于花中连向父亲的是匹配边的点,他的增广路显然是直接顺着父亲走,而如果连向父亲的边是非匹配边的点,那么显然是往后走然后跑过红色的横插边,然后再向上跑回关键点。
注意到如果连向父子的边是匹配边的点原先是不需要Father这个域来描述的,直接用表示匹配的那个域就可以了。但是现在在花中,他的Father这个域就要起作用了,用来向后指向,然后绕过红色横插边然后再跑回关键点。
实在是太精妙了。
//Problem:http://acm.timus.ru/problem.aspx?space=1&num=1099
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=;
int n;
int head;
int tail;
int Start;
int Finish;
int link[N]; //表示哪个点匹配了哪个点
int Father[N]; //这个就是增广路的Father……但是用起来太精髓了
int Base[N]; //该点属于哪朵花
int Q[N];
bool mark[N];
bool map[N][N];
bool InBlossom[N];
bool in_Queue[N]; void CreateGraph(){
int x,y;
scanf("%d",&n);
while (scanf("%d%d",&x,&y)!=EOF)
map[x][y]=map[y][x]=;
} void BlossomContract(int x,int y){
fill(mark,mark+n+,false);
fill(InBlossom,InBlossom+n+,false);
#define pre Father[link[i]]
int lca,i;
for (i=x;i;i=pre) {i=Base[i]; mark[i]=true; }
for (i=y;i;i=pre) {i=Base[i]; if (mark[i]) {lca=i; break;} } //寻找lca之旅……一定要注意i=Base[i]
for (i=x;Base[i]!=lca;i=pre){
if (Base[pre]!=lca) Father[pre]=link[i]; //对于BFS树中的父边是匹配边的点,Father向后跳
InBlossom[Base[i]]=true;
InBlossom[Base[link[i]]]=true;
}
for (i=y;Base[i]!=lca;i=pre){
if (Base[pre]!=lca) Father[pre]=link[i]; //同理
InBlossom[Base[i]]=true;
InBlossom[Base[link[i]]]=true;
}
#undef pre
if (Base[x]!=lca) Father[x]=y; //注意不能从lca这个奇环的关键点跳回来
if (Base[y]!=lca) Father[y]=x;
for (i=;i<=n;i++)
if (InBlossom[Base[i]]){
Base[i]=lca;
if (!in_Queue[i]){
Q[++tail]=i;
in_Queue[i]=true; //要注意如果本来连向BFS树中父结点的边是非匹配边的点,可能是没有入队的
}
}
} void Change(){
int x,y,z;
z=Finish;
while (z){
y=Father[z];
x=link[y];
link[y]=z;
link[z]=y;
z=x;
}
} void FindAugmentPath(){
fill(Father,Father+n+,);
fill(in_Queue,in_Queue+n+,false);
for (int i=;i<=n;i++) Base[i]=i;
head=; tail=;
Q[]=Start;
in_Queue[Start]=;
while (head!=tail){
int x=Q[++head];
for (int y=;y<=n;y++)
if (map[x][y] && Base[x]!=Base[y] && link[x]!=y) //无意义的边
if ( Start==y || link[y] && Father[link[y]] ) //精髓地用Father表示该点是否
BlossomContract(x,y);
else if (!Father[y]){
Father[y]=x;
if (link[y]){
Q[++tail]=link[y];
in_Queue[link[y]]=true;
}
else{
Finish=y;
Change();
return;
}
}
}
} void Edmonds(){
memset(link,,sizeof(link));
for (Start=;Start<=n;Start++)
if (link[Start]==)
FindAugmentPath();
} void output(){
fill(mark,mark+n+,false);
int cnt=;
for (int i=;i<=n;i++)
if (link[i]) cnt++;
printf("%d\n",cnt);
for (int i=;i<=n;i++)
if (!mark[i] && link[i]){
mark[i]=true;
mark[link[i]]=true;
printf("%d %d\n",i,link[i]);
}
} int main(){
// freopen("input.txt","r",stdin);
CreateGraph();
Edmonds();
output();
return ;
}
然后还有一篇,链接请猛戳。。
在北京冬令营的时候,yby提到了“带花树开花”算法来解非二分图的最大匹配。
http://builtinclz.abcz8.com/art/2012/ural1099.cpp
没错,这是用来解决URAL 1099 Work Schedule那题的。时间复杂度是O(N^3)
[转]带花树,Edmonds's matching algorithm,一般图最大匹配的更多相关文章
- Augmenting Path Algorithm : 一般图最大匹配
算法原理详见 http://www.csie.ntnu.edu.tw/~u91029/Matching.html orz 带花树很神奇,挖坑最大权匹配 #include <iostream> ...
- HDU-4687 Boke and Tsukkomi 带花树,枚举
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4687 题意:给一个无向图,求所有的最大匹配的情况所不包含的边.. 数据比较小,直接枚举边.先求一次最大 ...
- kuangbin带你飞 匹配问题 二分匹配 + 二分图多重匹配 + 二分图最大权匹配 + 一般图匹配带花树
二分匹配:二分图的一些性质 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j ...
- HDOJ 4687 Boke and Tsukkomi 一般图最大匹配带花树+暴力
一般图最大匹配带花树+暴力: 先算最大匹配 C1 在枚举每一条边,去掉和这条边两个端点有关的边.....再跑Edmonds得到匹配C2 假设C2+2==C1则这条边再某个最大匹配中 Boke and ...
- URAL1099. Work Scheduling(一般图匹配带花树开花算法)
1099. Work Scheduling Time limit: 0.5 second Memory limit: 64 MB There is certain amount of night gu ...
- HDU 4687 Boke and Tsukkomi 一般图匹配,带花树,思路,输出注意空行 难度:4
http://acm.hdu.edu.cn/showproblem.php?pid=4687 此题求哪些边在任何一般图极大匹配中都无用,对于任意一条边i,设i的两个端点分别为si,ti, 则任意一个极 ...
- URAL 1099. Work Scheduling (一般图匹配带花树)
1099. Work Scheduling Time limit: 0.5 secondMemory limit: 64 MB There is certain amount of night gua ...
- HDU 4687 Boke and Tsukkomi (一般图匹配带花树)
Boke and Tsukkomi Time Limit: 3000/3000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Othe ...
- ZOJ 3316 Game 一般图最大匹配带花树
一般图最大匹配带花树: 建图后,计算最大匹配数. 假设有一个联通块不是完美匹配,先手就能够走那个没被匹配到的点.后手不论怎么走,都必定走到一个被匹配的点上.先手就能够顺着这个交错路走下去,最后一定是后 ...
随机推荐
- ie6 iframe src="javascript:" 报安全警报问题
<iframe id="shuaka_iframe" class="embed-page-iframe" data-src="https://w ...
- POJ 1797 Heavy Transportation(Dijkstra)
http://poj.org/problem?id=1797 题意 :给出N个城市M条边,每条边都有容量值,求一条运输路线使城市1到N的运输量最大. 思路 :用dijkstra对松弛条件进行变形.解释 ...
- org.apache.http.ProtocolException: Target host is not specified
对于httpClient4.3访问指定页面,可以从下面的demo抽取方法使用. 注意:对于URL必须使用 http://开始,否则会有如下报错信息: Caused by: org.apache.htt ...
- NuGet相关的文章
NuGet学习笔记(1)——初识NuGet及快速安装使用http://www.cnblogs.com/zhwl/p/3377510.html NuGet学习笔记(2) 使用图形化界面打包自己的类库ht ...
- poj 3007 Organize Your Train part II(二叉排序树)
题目:http://poj.org/problem?id=3007 题意:按照图示的改变字符串,问有多少种..字符串.. 思路:分几种排序的方法,,刚开始用map 超时(map效率不高啊..),后来搜 ...
- 函数fseg_set_nth_frag_page_no
/**********************************************************************//** Sets the page number in ...
- Thread: BooleanRT : Realtime 3D boolean operations for (Runtime,Editor)
A Product by Mixed Dimensions What is BooleanRT? BooleanRT is a real-time 3D boolean operations exte ...
- 比较const ,readonly, stitac readonly
比较const ,readonly, stitac readonly: const和readonly的值一旦初始化则都不再可以改写: const必须在声明时初始化:readonly既可以在声明时初始化 ...
- HNOI2008明明的烦恼
写的很好的题解:http://www.cnblogs.com/zhj5chengfeng/archive/2013/08/23/3278557.html 我这种蒻蒻什么都不会啊…… 代码:(copy的 ...
- [swustoj 1095] 挖金子
挖金子(1095) 题目描述 你在一个N*M的区域中,一开始在(1,1)的位置,每个位置有可能有金子,也有可能不能到达,也有可能有传送门.你只能往右或者下走,不能走出这个区域.当你位于传送门时,传送门 ...