二分图的判定(染色法)和二分图最大匹配(匈牙利)算法及模板
Posted flyljz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二分图的判定(染色法)和二分图最大匹配(匈牙利)算法及模板相关的知识,希望对你有一定的参考价值。
定义
二分图也称二部图,是图论里的一种特殊模型,也是一种特殊的网络流。其最大的特点在于,可以将图里的顶点分为两个集合,且集合内的点没有直接关联,如下图所示。
如果某个图为二分图,那么它至少有两个顶点,且其所有回路的长度均为偶数,任何无回路的的图均是二分图。
1.染色法判断二分图
染色法是对每一个点深搜,与这个点连接的点颜色与此点相反,如果存在环且是偶数环或则不存在环,则满足该条件,如果存在奇数环则不满足(推出矛盾)
#include<iostream> #include<cstring> using namespace std; int h[100010],e[200010],ne[200010],idx; int color[100010];int n,m; void add(int a,int b) { e[idx]=b,ne[idx]=h[a],h[a]=idx++; } bool dfs(int u,int c) { color[u]=c; for(int i=h[u];i!=-1;i=ne[i]) { int j=e[i]; if(!color[j])//未被染色的话 { if(!dfs(j,3-c))return false; } else if(color[j]==c)//如果领结的点与本点颜色一样,则存在奇数环,不是二分图 return false; } return true; } int main() { memset(h,-1,sizeof h);cin>>n>>m; while(m--) { int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } int f=1; for(int i=1;i<=n;i++) { if(!color[i])//未被染色的话 { if(!dfs(i,1)) { f=0; break; } } } if(f)printf("Yes "); else printf("No "); return 0; }
2.匈牙利算法求二分图的最大匹配
首先介绍两个概念:
二分图的匹配:给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。
二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。
从左边的二分图一一枚举匹配右边(所以存从左边到右边的有向边就行),对于左边每一个点所连接的右边部分来说,
如果在这次循环时未被枚举,且未匹配左边的点或则匹配的左边的可以连接其他右边部分的点(递归实现)则该点可以匹配此时右边的点
#include<iostream> #include<cstring> using namespace std; int n1,n2,m; int h[510],e[100010],ne[100010],idx; int match[510];//存与n2匹配的n1 int vis[510];//每一个循环时判断n2是否已经有了匹配; void add(int a,int b) { e[idx]=b;ne[idx]=h[a];h[a]=idx++; } bool find(int x) { for(int i=h[x];i!=-1;i=ne[i]) { int j=e[i]; if(!vis[j])//此时n2未被选择 { vis[j]=1; if(match[j]==0||find(match[j]))//如果此时n2未被n1选择,或则与n2选择的n1有其他的选择 { match[j]=x; return true; } } } return false; } int main() { cin>>n1>>n2>>m; memset(h,-1,sizeof h); while(m--) { int a,b; scanf("%d%d",&a,&b); add(a,b); } int res=0; for(int i=1;i<=n1;i++) { memset(vis,0,sizeof(vis)); if(find(i))res++; } cout<<res<<endl; return 0; }
以上是关于二分图的判定(染色法)和二分图最大匹配(匈牙利)算法及模板的主要内容,如果未能解决你的问题,请参考以下文章
图论二分图的应用(染色法判断二分图,最大匹配,最小点覆盖,最大独立集,最小路径点覆盖,最小路径重复点覆盖)