二分图

二分图

定义

二分图,又称二部图,英文名叫 Bipartite graph。

二分图是什么?节点由两个集合组成,且两个集合内部没有边的图。

换言之,存在一种方案,将节点划分成满足以上性质的两个集合。

二分图的判定

定理 :一张无向图是二分图,当且仅当图中不存在奇环;

根据该定理,我们可以用染色法进行二分图的判定;

void dfs(int u,int color){
	c[u]=color;
	for(int i=head[u];i;i=e[i].nxt){
		int to=e[i].v;
		if(c[to]==c[u]) flag=1;
		if(c[to]==-1) dfs(to,3-color);
	}
}

P1525 [NOIP2010 提高组] 关押罪犯

P1155 [NOIP2008 提高组] 双栈排序

二分图匹配

任意两条边都没有公共端点的变的集合被称为图的一组 匹配

包含变数最多的一组匹配被称为 最大匹配

对于任意一组匹配 S ,属于S的边被称为 匹配边

反之则为 不匹配边

如果在二分图存在一条连接连个非匹配点的路径 $ psth $ ,使得非匹配边与匹配边在 $ path $ 上交替出现,那么称 $ path $ 是匹配 $ S $ 的增广路,也称交错路;

可以发现把增光路取反的话,匹配边会增加一;

匈牙利算法

听我口胡

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=510;
const int M=5e4+7;
struct edge{
	int v,nxt;
}e[M];
int n,m,ee,ans,cnt;
int head[N],match[N],vis[N];
void add_edge(int u,int v){
	e[++cnt]=(edge){v,head[u]};
	head[u]=cnt;
}
int dfs(int u){
	for(int i=head[u];i;i=e[i].nxt){
		int to=e[i].v;
		if(vis[to]) continue;
		vis[to]=1;
		if(!match[to]||dfs(match[to])){
			match[to]=u;
			return 1;
		}
	}
	return 0;
}
int main(){
	scanf("%d%d%d",&n,&m,&ee);
	for(int i=1;i<=ee;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		add_edge(x,y);
	}
	for(int i=1;i<=n;i++){
		memset(vis,0,sizeof(vis));
		if(dfs(i)){
			ans++;
		}
	}
	cout<<ans;
}

时间复杂度是 $ O(N*M) $ $ 读者自证 $

完备匹配

二分图左右节点数相同,均为N个节点,如果该二分图的最大匹配包含N条匹配边,称该二分图具有完备匹配。

多重匹配

每个点的限制不是一。

最小点覆盖

在二分图中寻找一个尽量小的点集,使图中每一条边至少有一个点在该点集中。

最小点覆盖=最大匹配

二分图最大匹配的König定理及其证明

二分图最小独立集 = 二分图点的个数 - 最小点覆盖 = 二分图点的个数 - 最大匹配

P3386 【模板】二分图最大匹配

P1129 [ZJOI2007] 矩阵游戏

P2055 [ZJOI2009]假期的宿舍

P1640 [SCOI2010]连续攻击游戏

Asteroids 穿越小行星群

UVA1194 Machine Schedule

P4304 [TJOI2013]攻击装置

P1963 [NOI2009] 变换序列

posted @ 2021-01-17 15:25  Aswert  阅读(419)  评论(0编辑  收藏  举报