二分图
- 定义
图为二分图当且仅当图中不存在奇数环
简单证明一下:
我们把这些点分为两个集合 假设1为集合1 那么2为集合2 集合3为集合1 1为集合2
矛盾!!!所以不能出现奇数环
二分图的判定方法
dfs染色法
我们任意选择起点然后染其邻接点(邻接点染为相反颜色) 表示两个集合 如果出现矛盾那么就不是二分图(当前染的点的邻接点有颜色 但是和当前点的颜色相同 这就是矛盾) 用图模拟下:
首先把任意一个点染为黑色
那么它的邻接点都是白色
然后白色邻接点都是黑色 这就是一个完美的二分图!!!
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int h[N],e[N],ne[N],color[N],idex,n,m;
void add(int a,int b){
e[idex]=b;
ne[idex]=h[a];
h[a]=idex++;
} //邻接表建立二分图
bool dfs(int x,int c){
color[x]=c;//c表示当前颜色
for(int i=h[x];i!=-1;i=ne[i]){//遍历其邻接点
if(!color[e[i]]){//如果没有被染色就染为相反的颜色
if(!dfs(e[i],3-c))return false;//邻接点染为相反颜色出现矛盾
}
else if(color[e[i]]==c)return false;//当前点出现矛盾
}
return true;
}
int main(){
memset(h,-1,sizeof(h));
cin>>n>>m;
int a,b;
while(m--){
cin>>a>>b;
add(a,b),add(b,a);
}
bool flag=true;
for(int i=1;i<=n;i++){
if(!color[i]){
if(!dfs(i,1))flag=false;
}
}
if(flag)cout<<"yes"<<endl;
else cout<<"no"<<endl;
}
应用
匈牙利最大匹配图:
因为二分图可以看成两个集合所以就可以把图看下图:
左为集合1右为集合2 那么二分图的匹配就是 左边集合的点对应一个右边集合的点 而且
右边集合只能对应一个左边的点(一一对应) 最大匹配就是左边最多几个点和左边的一一匹配
简单介绍一下匈牙利算法
从左边最上面的点开始加入左1匹配了右1到左2的时候2只能匹配右1 那么我们回溯到左1看左1是否有其他点可以匹配 如果有那么让左1匹配其他点 然后左2匹配右1(大体思路就是这样)
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=510,M=100010;
int n1,n2,m;
int h[N],e[M],ne[M],idex;
int match[N];//记录右边的点匹配的是哪一个点
bool st[N];//标记当前点是否被考虑过;
void add(int a,int b){
e[idex]=b;
ne[idex]=h[a];
h[a]=idex++;
}
bool Find(int x){
for(int i=h[x];i!=-1;i=ne[i]){
if(!st[e[i]]){
st[e[i]]=true;
if(!match[e[i]]||Find(match[e[i]])){
match[e[i]]=x;
return true;
}
}
}
return false;
}
int main(){
cin>>n1>>n2>>m;
memset(h,-1,sizeof(h));
int a,b;
while(m--){
cin>>a>>b;
add(a,b);
}
int ans=0;
for(int i=1;i<=n1;i++){
memset(st,0,sizeof(st));
if(Find(i))ans++;
}
cout<<ans<<endl;
}