1.自然语言描述
二分图:设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集(i in A,j in B),则称图G为一个二分图。(摘自百度百科)
图G是二分图的充要条件是G中不含奇数环。
二分图的匹配:设M为G的子图,M中的任意两条边都不依附于同一个顶点,则称M为G的一个匹配。
最大匹配:M中边数最多的情况。
匈牙利算法:找出二分图的最大匹配。策略是:左集合中的每一个点找自己的邻接点做匹配点;如果邻接点已经被别的左集合点匹配了,那就找到这个邻接点所匹配的那个左集合点,让它换一个邻接点去匹配。直到所有的左集合点都被遍历过为止。
2.代码描述
题目:Acwing.860 染色法判定二分图题目链接
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=1e5+10;
int n,m,h[MAXN],e[2*MAXN],ne[2*MAXN],idx;
int color[MAXN];
//二分图充要条件:图G是二分图<=>G中不含奇数环(有奇数环就意味着这个环中有着奇数个点,必然会出现邻接的两个点颜色相同,不能被二分染色)
void add(int a,int b)
{
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
bool calc(int x,int c)
{
color[x]=c;
for(int i=h[x];i!=-1;i=ne[i]){
int j=e[i];
if(!color[j]&&!calc(j,3-c))//1.邻接点未染色,递归染色
return false;
else if(color[j]==c)//2.邻接点染色雷同,则说明不是二分图
return false;
}
return true;
}
int main(void)
{
cin>>n>>m;
memset(h,-1,sizeof(h));
for(int i=0;i<m;i++){
int a,b;
cin>>a>>b;
add(a,b),add(b,a);
}
bool flag=true;
for(int i=1;i<=n;i++)
if(!color[i]){
if(!calc(i,1)){
flag=false;
break;
}
}
printf("%s\n",flag?"Yes":"No");
return 0;
}
题目:Acwing.861 二分图的最大匹配题目链接
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=1e5+10;
int n1,n2,m,h[MAXN],e[2*MAXN],ne[2*MAXN],match[MAXN],idx,ans;
bool st[MAXN];
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(!st[j]){
st[j]=true;
if(!match[j]||find(match[j])){//当前邻接点未匹配,或者匹配了但是能够让与他匹配的n1集合的点找另一个邻接点去匹配
match[j]=x;
return true;//匹配成功
}
}
}
return false;//没有能够匹配的点,匹配失败
}
int main(void)
{
cin>>n1>>n2>>m;
memset(h,-1,sizeof(h));
for(int i=0;i<m;i++){
int a,b;
cin>>a>>b;
add(a,b);
}
for(int i=1;i<=n1;i++){
memset(st,false,sizeof(st));
if(find(i))
ans++;
}
cout<<ans<<endl;
return 0;
}