二分图
二分图
定义
二分图,又称二部图,英文名叫 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);
}
}
二分图匹配
任意两条边都没有公共端点的变的集合被称为图的一组 匹配。
包含变数最多的一组匹配被称为 最大匹配
对于任意一组匹配 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条匹配边,称该二分图具有完备匹配。
多重匹配
每个点的限制不是一。
最小点覆盖
在二分图中寻找一个尽量小的点集,使图中每一条边至少有一个点在该点集中。
最小点覆盖=最大匹配
二分图最小独立集 = 二分图点的个数 - 最小点覆盖 = 二分图点的个数 - 最大匹配