开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第3天,点击查看活动详情
二分图基础
二分图,又叫二部图,简而言之,就是顶点集V可分割为两个互不相交的子集,并且图中每条边依附的两个顶点都分属于这两个互不相交的子集,两个子集内的顶点不相邻的图。
染色法判定二分图
基本性质: 一个图是二分图等价于该图中不含有奇数环,这是一个充要条件
我们通过将节点染成不同的颜色,以此标记它们所属的集合,不含奇数环,染色就没有矛盾
判定原理: 一个图在染色过程中,出现矛盾,则不是二分图,否则就是二分图
染色过程我们可以借助DFS或者BFS实现
代码实现:
例题:给你n个顶点m个边的图,输入为m行,每行两个数表示边,输出为"Yes"或者“No”表示是不是二分图
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=1e5+10,M=2e5+20;
int h[N],e[M],ne[M],idx;
int color[N];
bool st[N];
int n,m;
void add(int a,int b){
e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
bool dfs(int x,int c){
color[x]=c;
for(int i=h[x];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(){
cin>>n>>m;
memset(h,-1,sizeof h);
while(m--){
int a,b;
cin>>a>>b;
add(a,b);
add(b,a);
}
bool flag=true; //flag记录是否出现矛盾
for(int i=1;i<=n;i++){ //for循环,找没染色的点
if(!color[i]){
if(!dfs(i,1)){
flag=false;
break;
}
}
}
if(flag) puts("Yes");
else puts("No");
return 0;
}
匈牙利算法
匈牙利算法常被用于求解二分图的最大匹配问题
二分图的匹配: 给定一个二分图 G,在 GG的一个子图 M 中,M的边集 {E} 中的任意两条边都不依附于同一个顶点,则称 M 是一个匹配。
二分图的最大匹配: 所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。
算法步骤:
我们不妨把二分图的两个部分看作是男和女
1.遍历每个男生,每次遍历将vis数组清空,vis数组是为了保证对于每个男生而言,每个女生只考虑一次
2.每次考虑的时候,遍历该男生"看中"(相接)的所有女生,如果对应女生没有与其他男生匹配或是匹配的男生有“备胎”,那么这对男女就匹配,统计匹配成功的数量,就是二分图的最大匹配
由上述分析可知,该算法的时间复杂度是O(mn)
代码实现:
例题:
给定一个二分图,其中左半部包含 n1 个点(编号 1∼n1),右半部包含 n2 个点(编号 1∼n2),二分图共包含 m条边。
数据保证任意一条边的两个端点都不可能在同一部分中。
请你求出二分图的最大匹配数。
输入:
第一行包含三个整数 n1、 n2 和 m。
接下来 m 行,每行包含两个整数 u 和 v,表示左半部点集中的点 u 和右半部点集中的点 v之间存在一条边。
输出:
输出一个整数,表示二分图的最大匹配数。
AC Code:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=1e5+10,M=4e5+10;
int n1,n2,m;
int e[M],ne[M],h[N],idx;
void add(int a,int b){
e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
int match[N];
bool st[N];
bool find(int x){
for(int i=h[x];~i;i=ne[i]){
int j=e[i];
if(!st[j]){
st[j]=true;
if(match[j]==0||find(match[j])){
match[j]=x;
return true;
}
}
}
return false;
}
int main(){
cin>>n1>>n2>>m;
memset(h,-1,sizeof h);
while(m--){
int a,b;
cin>>a>>b;
add(a,b);
}
int res=0;
for(int i=1;i<=n1;i++){
memset(st,0,sizeof st);
if(find(i))res++;
}
cout<<res<<endl;
return 0;
}