二分图匹配
2015-08-10 12:41
309 查看
二分图匹配
1.一个二分图中的最大匹配数等于这个图中的最小点覆盖数
König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数。如果你还不知道什么是最小点覆盖,我也在这里说一下:假如选了一个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点来覆盖所有的边。
2.最小路径覆盖=最小路径覆盖=|G|-最大匹配数
在一个N*N的有向图中,路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联;(如果把这些路径中的每条路径从它的起始点走到它的终点,那么恰好可以经过图中的每个顶点一次且仅一次);如果不考虑图中存在回路,那么每每条路径就是一个弱连通子集.
由上面可以得出:
1)一个单独的顶点是一条路径;
2)如果存在一路径p1,p2,......pk,其中p1 为起点,pk为终点,那么在覆盖图中,顶点p1,p2,......pk不再与其它的
顶点之间存在有向边.
最小路径覆盖就是找出最小的路径条数,使之成为G的一个路径覆盖.
路径覆盖与二分图匹配的关系:最小路径覆盖=|G|-最大匹配数;
3.二分图最大独立集=顶点数-二分图最大匹配
独立集:图中任意两个顶点都不相连的顶点集合。
总结:对于二分匹配,有一个集合X,有一个集合Y,X、Y集合内部无联系,之间有联系,X集合连接Y集合,则dfs时对Y集合的每个找其匹配是否为X集合的u,hunger时对X集合的每个点遍历是否匹配
一、匈牙利算法
顶点编号从0开始的
优点:适用于稠密图,DFS找增广路,实现简洁易于理解
二、Hopcroft-Carp算法
这个算法比匈牙利算法的时间复杂度要小,大数据可以采用这个算法、需要queue头文件
1.一个二分图中的最大匹配数等于这个图中的最小点覆盖数
König定理是一个二分图中很重要的定理,它的意思是,一个二分图中的最大匹配数等于这个图中的最小点覆盖数。如果你还不知道什么是最小点覆盖,我也在这里说一下:假如选了一个点就相当于覆盖了以它为端点的所有边,你需要选择最少的点来覆盖所有的边。
2.最小路径覆盖=最小路径覆盖=|G|-最大匹配数
在一个N*N的有向图中,路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点,且任何一个顶点有且只有一条路径与之关联;(如果把这些路径中的每条路径从它的起始点走到它的终点,那么恰好可以经过图中的每个顶点一次且仅一次);如果不考虑图中存在回路,那么每每条路径就是一个弱连通子集.
由上面可以得出:
1)一个单独的顶点是一条路径;
2)如果存在一路径p1,p2,......pk,其中p1 为起点,pk为终点,那么在覆盖图中,顶点p1,p2,......pk不再与其它的
顶点之间存在有向边.
最小路径覆盖就是找出最小的路径条数,使之成为G的一个路径覆盖.
路径覆盖与二分图匹配的关系:最小路径覆盖=|G|-最大匹配数;
3.二分图最大独立集=顶点数-二分图最大匹配
独立集:图中任意两个顶点都不相连的顶点集合。
总结:对于二分匹配,有一个集合X,有一个集合Y,X、Y集合内部无联系,之间有联系,X集合连接Y集合,则dfs时对Y集合的每个找其匹配是否为X集合的u,hunger时对X集合的每个点遍历是否匹配
一、匈牙利算法
顶点编号从0开始的
优点:适用于稠密图,DFS找增广路,实现简洁易于理解
const int maxn=510; int uN,vN;//u,v数目,uN是匹配左边的顶点数,vN是匹配右边的顶点数 int g[maxn][maxn];//初始化:g[][]两边顶点的划分情况,建立g[i][j]表示i->j的有向边就可以了,是左边向右边的匹配 int linker[maxn]; bool used[maxn]; bool dfs(int u)//从左边开始找增广路径 { int v; for(v=0;v<vN;v++)//这个顶点编号从0开始,若要从1开始需要修改 if(g[u][v]&&!used[v]) { used[v]=true; if(linker[v]==-1||dfs(linker[v])) {//找增广路,反向 linker[v]=u; return true; } } return false;//这个不要忘了,经常忘记这句 } int hungary()//输出最大匹配数 { int res=0; int u; memset(linker,-1,sizeof(linker)); for(u=0;u<uN;u++) { memset(used,0,sizeof(used)); if(dfs(u)) res++; } return res; }
二、Hopcroft-Carp算法
这个算法比匈牙利算法的时间复杂度要小,大数据可以采用这个算法、需要queue头文件
const int maxn=3000; const int INF=1<<28; int g[maxn][maxn],Mx[maxn],My[maxn],Nx,Ny;//初始化:g[][]邻接矩阵 int dx[maxn],dy[maxn],dis; bool vst[maxn]; bool searchP() { queue<int>Q; dis=INF; memset(dx,-1,sizeof(dx)); memset(dy,-1,sizeof(dy)); for(int i=0;i<Nx;i++) if(Mx[i]==-1) { Q.push(i); dx[i]=0; } while(!Q.empty()) { int u=Q.front(); Q.pop(); if(dx[u]>dis) break; for(int v=0;v<Ny;v++) if(g[u][v]&&dy[v]==-1) { dy[v]=dx[u]+1; if(My[v]==-1) dis=dy[v]; else { dx[My[v]]=dy[v]+1; Q.push(My[v]); } } } return dis!=INF; } bool DFS(int u) { for(int v=0;v<Ny;v++) if(!vst[v]&&g[u][v]&&dy[v]==dx[u]+1) { vst[v]=1; if(My[v]!=-1&&dy[v]==dis) continue; if(My[v]==-1||DFS(My[v])) { My[v]=u; Mx[u]=v; return 1; } } return 0; } int MaxMatch() { int res=0; memset(Mx,-1,sizeof(Mx));//调用:res=MaxMatch(); Nx,Ny要初始化!!! memset(My,-1,sizeof(My)); while(searchP()) { memset(vst,0,sizeof(vst)); for(int i=0;i<Nx;i++) if(Mx[i]==-1&&DFS(i)) res++; } return res; }
相关文章推荐
- KVC 与 KVO 理解
- OC循环渐进:类目和延展
- 弃聪明,求质朴
- js 上传图片预览
- Python IDLE快捷键一览
- 效果非常好的 Jquery弹出层插件 jQuery Sweet alert
- 【Qt OpenGL教程】23:球面映射
- jquery插件jquery.nicescroll实现图片无滚动条左右拖拽的方法
- hdu3944 DP? (lucas定理+预处理)
- 在CentOS上搭建PHP服务器环境
- pl/python调用aerospike
- ISO 9126质量模型:软件质量模型的6大特性和27个子特性
- codeforce 567C
- 信号处理篇
- leetCode #235 Lowest Common Ancestor of a Binary Search Tree
- ZOJ 3299 Fall the Brick (线段树)
- string.replaceAll Illegal group reference"异常的分析
- BZOJ 3373: [Usaco2004 Mar]Lying Livestock 说谎的牲畜( 差分约束 )
- Mark:Ajax参数中文编码乱码问题
- 多线程Socket小程序 Socket加法