二分图匹配
定义
二分图
二分图(bipartite graph)指的是满足 图的所有结点可以分成两个集合,每个集合内的点没有连边,两个集合之间可以有连边 的图 。
判断一张图是否是二分图?
从一个集合出发,回到这个集合的路径的长度一定为奇数。 (必要条件)
二分图匹配
一个匹配称为从一个集合中的某点到另一个集合中的某点的连线。一个点最多能产生一的贡献(如果连了很多条边,从中选择一条)。
问最大的匹配数。
二分图匹配算法
匈牙利算法!
模板见例题
应用
最大匹配数
http://acm.hdu.edu.cn/showproblem.php?pid=2063
点击查看代码
//二分图匹配
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1005;
int n,m,k;  //a方n人 b方m人 k对关系 
int u,v;  
int g[N][N]; //表示a,b之间有关系,赋值为0/1. 
//!若要去掉某一关系,令其=0即可  
int match[N];  //下标是配对的b方  值为对应的a方 
bool reserve_b[N];  //标记b方是否已经使用过 
int ans;
bool dfs(int x){
	for(int i=1;i<=m;i++){  //b方 
		if(!reserve_b[i]&&g[x][i]){
			reserve_b[i]=1;
			if(!match[i]||dfs(match[i])){  //b无配对 或者 b的原配可以找到新的配对 
				match[i]=x;  //则令x为b的配对 
				return 1;  //x找到了配对 
			}
		}
	}
	return 0;  //x没有找到配对 
}
int main(){
//	while(scanf("%d%d%d",&n,&m,&k)==3){
		scanf("%d%d%d",&n,&m,&k);
		memset(g,0,sizeof(g)); 
		memset(match,0,sizeof(match));
		for(int i=1;i<=k;i++){
			scanf("%d%d",&u,&v);
			g[u][v]=1;  // 表示a,b之间有关系,也可以表示两点间有一条边 
		}
		for(int i=1;i<=n;i++){  //a方 
			memset(reserve_b,0,sizeof(reserve_b));  //不加会错
			//表示不论bi之前是否有配对,都不会影响它与ai的配对 
			if(dfs(i)) ans++;  //ai配对成功后配对数++,虽然可能更换配对,但是保证ai一定有配对 
		}
		printf("%d\n",ans);
//	}
	return 0;
} 
二分图最小点覆盖
最小点覆盖问题是说,假设选择一个点,也同时覆盖了这个点连向的所有点(无向边),需要求出最少需要选择的点使得所有点都至少被覆盖了一次。
证明用到了 \(konig\) 定理!
结论:二分图最大匹配数 = 二分图最小点覆盖
直观来想,因为点覆盖覆盖了所有的点,所以它可能是比较大的。假设存在一个下限,又发现当取最大匹配数的时候恰好成立。那么可以更小吗?如果比最大匹配数还小,那肯定存在两个点可以连边但是都没有选择的情况,是不合法的,因此得证。
二分图最小路径覆盖
有向边
结论:二分图最小点覆盖 = 边的数量-二分图最大匹配数
二分图最大独立集
最大独立集:选最多的点,满足两两之间没有边相连。
在最小点覆盖中,每条边最少被选了一个顶点,因此最大独立集中 每条边最多被选了一个顶点,满足独立集条件。
数量 = 边的数量-二分图最大匹配数
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号