在此,借鉴了DY大神的代码传送门 Orz
还有一篇讲原理的博客,也写得好传送门Orz
总的来说带花树是用来进行一般图的最大匹配,
下面来解释一下带花树。
核心:找增广路。
具体操作:
(对于每一个搜出来的点都进行颜色的赋值)
1.增广路
假设已经匹配好了一堆点,我们从一个没有匹配的节点s开始,使用BFS生成搜索树。每当发现一个节点u,如果u还没有被匹配,那么就可以进行一次成功的增广;否则,我们就把节点u和它的配偶v一同接到树上,之后把v丢进队列继续搜索。
2.如果搜到了被访问过的点(其实就是遇到环了),那么就对环进行判断。
如果是偶环,即最后的点与出发的点颜色不相同,则无视那条边。
如果是奇环,即最后的点与出发的点颜色相同,就进行缩花(差不多就是缩点)。
3.缩花:
首先找x,y的LCA–p。(暴力也可以)
在Next[]中将x,y进行互连(形成一个环)。
在并查集中进行操作,将花中的每条边改成双向(无向图)。
同时将每个点的颜色都改为LCA的颜色。
4.继续以上操作,直到找不到增广路
以下代码为ural1099的代码题目
link[]代表它的配偶
G[]存图
Next[]它在增广路的前驱
fa[]并查集中的父亲
type[]是代表他的颜色
vis[]代表是否被访问过
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#define type Type
#define For(aa,bb,cc) for(int aa=bb;aa<=cc;++aa)
#define ak(aa) memset(aa,0,sizeof(aa))
#define next Next
using namespace std;
const int maxn=1010;
bool G[maxn][maxn],p[maxn];
int link[maxn],fa[maxn],next[maxn],type[maxn];
int n,ans;
queue<int>q;
/*带花树模板*/
struct Blossom_Tree{
/*并查集维护*/
int find(int x){
return x==fa[x]?x:find(fa[x]);
}
/*
将x和LCA连起来,
将环中的所有颜色改成LCA的颜色
将环中改为无向图,并改为同一个并查集
*/
void combine(int x,int y){
while(x!=y){
int u=link[x],v=next[u];
if(find(v)!=y) next[v]=u;
if(type[u]==1) type[u]=2,q.push(u);
fa[find(x)]=find(u),fa[find(u)]=find(v);
x=v;
}
return ;
}
void contract(int x,int y){
ak(p);
int LCA=0;
/*暴力LCA*/
for(int i=x;i;i=next[link[i]]) i=find(i),p[i]=1;
for(int i=y;i;i=next[link[i]]){
i=find(i);
if(p[i]){
LCA=i;
break;
}
}
/*改双向边,且满足缩花的操作*/
if(find(x)!=LCA) next[x]=y;
if(find(y)!=LCA) next[y]=x;
combine(x,LCA);
combine(y,LCA);
return ;
}
void bfs(int start){
while(!q.empty()) q.pop();
ak(type),ak(next);
For(i,1,n) fa[i]=i;
q.push(start),type[start]=1;
while(!q.empty()){
int k=q.front();q.pop();
For(i,1,n){
if(!G[k][i] || find(k)==find(i) || link[k]==i || type[i]==1) continue;
/*不联通中,在同一个并查集中,互为配偶,偶环*/
if(type[i]==2) contract(k,i);//奇环,缩花
else if(link[i]){//将配偶加入队列
next[i]=k;
type[i]=1;
type[link[i]]=2;
q.push(link[i]);
}else{//成功增广
next[i]=k;
int pos=i,u=next[pos],v=link[u];
while(pos){
link[u]=pos,link[pos]=u;
pos=v;
u=next[pos],v=link[u];
}
return ;
}
}
}
return ;
}
}Tree;
int main(){
scanf("%d",&n);
int x,y;
while(scanf("%d%d",&x,&y)!=EOF){
G[x][y]=1,G[y][x]=1;
}
For(i,1,n){
if(!link[i]) Tree.bfs(i);
}
For(i,1,n){
if(link[i]) ++ans;
}
printf("%d\n",ans);
For(i,1,n){
if(link[i] && i<link[i]){
printf("%d %d\n",i,link[i]);
}
link[i]=-1;
}
return 0;
}