【总结】一般图最大匹配
2018-02-23 11:38
197 查看
二分图最大匹配:
首先我们回顾一下二分图最大匹配的算法:匈牙利算法
我们的方法是不停地寻找一条增广路,以增加我们的答案。其实带花树也是一样的思路,我们同样是寻找增广路。如果将匈牙利算法照搬到一般图上,我们会发现,算法是无法进行的。而问题出在奇环上。匈牙利算法,是基于反转操作的,每次找到一条增广路径,就将路径上所有的选择情况反转,以得到一个更大的匹配。但如果在一般图中,在增广路径走到奇环时,就会出现反转后矛盾的问题。
如上图,虚线表示未选择的边,实线表示已选择的边,如果从A出发,可以找到一条增广路径:
A->B->C->D->E->C->B->F
的确这条路径是一条交错轨,但很容易发现:如果将每条边的选择情况反转,那么边DC与边CE就会冲突,边AB与边BF也会冲突。
注:这是论文上的图,但我个人认为这个图所反映的问题是不会出现的,因为我们在匈牙利算法中会标记访问,所以不可能走环,但似乎标记访问会造成其他问题。
如果是偶环,则不会对算法的正确性有影响(毕竟二分图中都可能出现偶环)。
所以,我们所有的问题就集中在了奇环上。
经过刚才的讨论,问题都集中在了奇环上,所以带花树最大的目标,就是解决奇环对算法的影响。
首先,我们仍然当做是二分图来做:
仍然是暴力找增广路径,对于我们枚举到的相邻点v
若v未访问过:
1、若v已经匹配,则从v开始继续bfs
2、若v未匹配,则找到一条增广路
若v访问过,则找到一个环:
1、若为偶环,直接忽略,跳过当前节点
2、若为奇环,则将当前的环暴力缩点,将环缩成一朵陈村花
以下证明摘自论文(爱看不看):
以上就是一般图最大匹配的带花树算法。
模板题:UOJ79
但是,关于一般图最大匹配,还有一个算法:
其时间复杂度实测比带花树略慢,但代码相对容易实现
首先我们回顾一下二分图最大匹配的算法:匈牙利算法
我们的方法是不停地寻找一条增广路,以增加我们的答案。其实带花树也是一样的思路,我们同样是寻找增广路。如果将匈牙利算法照搬到一般图上,我们会发现,算法是无法进行的。而问题出在奇环上。匈牙利算法,是基于反转操作的,每次找到一条增广路径,就将路径上所有的选择情况反转,以得到一个更大的匹配。但如果在一般图中,在增广路径走到奇环时,就会出现反转后矛盾的问题。
如上图,虚线表示未选择的边,实线表示已选择的边,如果从A出发,可以找到一条增广路径:
A->B->C->D->E->C->B->F
的确这条路径是一条交错轨,但很容易发现:如果将每条边的选择情况反转,那么边DC与边CE就会冲突,边AB与边BF也会冲突。
注:这是论文上的图,但我个人认为这个图所反映的问题是不会出现的,因为我们在匈牙利算法中会标记访问,所以不可能走环,但似乎标记访问会造成其他问题。
如果是偶环,则不会对算法的正确性有影响(毕竟二分图中都可能出现偶环)。
所以,我们所有的问题就集中在了奇环上。
带花树算法:
虽然看名字,带花树很像是某种数据结构,但它并不是数据结构,而是一种类似于匈牙利算法的图论算法。它之所以称为“树”,是因为它可以将一个图看做一颗树的形式来解决问题,这一点上它又很类似于tarjan算法。经过刚才的讨论,问题都集中在了奇环上,所以带花树最大的目标,就是解决奇环对算法的影响。
首先,我们仍然当做是二分图来做:
仍然是暴力找增广路径,对于我们枚举到的相邻点v
若v未访问过:
1、若v已经匹配,则从v开始继续bfs
2、若v未匹配,则找到一条增广路
若v访问过,则找到一个环:
1、若为偶环,直接忽略,跳过当前节点
2、若为奇环,则将当前的环暴力缩点,将环缩成一朵陈村花
以下证明摘自论文(爱看不看):
以上就是一般图最大匹配的带花树算法。
模板题:UOJ79
#include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<vector> #define SF scanf #define PF printf #define MAXN 510 using namespace std; int mk[MAXN],fa[MAXN],nxt[MAXN],q[MAXN],vis[MAXN],match[MAXN]; int fr,bk,t,n,m; vector<int> a[MAXN]; int find(int x){ if(fa[x]==x) return x; fa[x]=find(fa[x]); return fa[x]; } int LCA(int x,int y){ t++; while(1){ if(x){ x=find(x); if(vis[x]==t) return x; vis[x]=t; if(match[x]) x=nxt[match[x]]; else x=0; } swap(x,y); } } void Union(int x,int y){ if(find(x)!=find(y)) fa[fa[x]]=fa[y]; } void gr(int a,int p){ while(a!=p){ int b=match[a]; int c=nxt[b]; if(find(c)!=p) nxt[c]=b; if(mk[b]==2){ q[++bk]=b; mk[b]=1; } Union(a,b); Union(b,c); a=c; } } void aug(int S){ for(int i=1;i<=n;i++){ mk[i]=nxt[i]=0; fa[i]=i; } mk[S]=1; fr=bk=0; q[fr]=S; while(fr<=bk){ int x=q[fr++]; for(int i=0;i<a[x].size();i++){ int y=a[x][i]; if(match[x]==y) continue; else if(find(x)==find(y)) continue; else if(mk[y]==2) conti 4000 nue; else if(mk[y]==1){ int r=LCA(x,y); if(find(x)!=r) nxt[x]=y; if(find(y)!=r) nxt[y]=x; gr(x,r); gr(y,r); } else if(!match[y]){ nxt[y]=x; for(int u=y;u;){ int v=nxt[u]; int mv=match[v]; match[u]=v; match[v]=u; u=mv; } return; } else{ nxt[y]=x; mk[y]=2; q[++bk]=match[y]; mk[match[y]]=1; } } } } int main(){ SF("%d%d",&n,&m); int u,v; for(int i=1;i<=m;i++){ SF("%d%d",&u,&v); a[u].push_back(v); a[v].push_back(u); } for(int i=1;i<=n;i++) if(!match[i]) aug(i); int sum=0; for(int i=1;i<=n;i++) if(match[i]) sum++; PF("%d\n",sum/2); for(int i=1;i<=n;i++) PF("%d ",match[i]); }
但是,关于一般图最大匹配,还有一个算法:
其时间复杂度实测比带花树略慢,但代码相对容易实现
Tutte矩阵
(待补)相关文章推荐
- 【BZOJ4405】挑战NPC 带花树模板 一般图最大匹配
- [一般图最大匹配 带花树] BZOJ 4405
- 二分图最大匹配总结【转自kb神】
- [特殊的一般图最大匹配] BZOJ 4874 筐子放球
- 二分图最大匹配总结
- UOJ79 一般图最大匹配
- UOJ #79. 一般图最大匹配
- uoj#79. 一般图最大匹配【带花树模板】
- 二分图最大匹配总结(转)
- UOJ 一般图的最大匹配(带花树算法模板)
- 【learning】一般图最大匹配——带花树
- hdu 3446 daizhenyang's chess 一般图最大匹配+博弈 在一个棋盘上,两个人轮流走,每个人可以移动king走到没被走过的幸运的格子上。问,先手是否能赢。
- uoj #79. 一般图最大匹配 带花树算法
- Tutte矩阵求一般图最大匹配
- 【UOJ】#79. 一般图最大匹配
- 二分图最大匹配总结
- #79. 一般图最大匹配(带花树算法)
- 二分图最大匹配总结
- KM算法的简单总结 二部图的最大权匹配
- 二分图最大匹配总结(匈牙利算法)