【概念】
在一张图中,如果能够把全部的点分到两个集合中,保证两个集合内部没有 任何边 ,图中的边只存在于两个集合之间,这张图就是二分图。
换句话说,二分图中不存在连接同一集合的不同点的边。
Forexample:
【常用算法】
1.染色法(判断一个图是否为二分图)
2.匈牙利算法(求二分图的最大匹配数)
【分析】
1.首先,对任意一个没有被染色的点染色。
2.然后判断其相邻的顶点是否染色。
如果没有,则染上相反的颜色;
如果已经染色且与原点的颜色相同,说明与二分图的定义存在矛盾,则该图不是二分图。
3.以上过程可以用bfs或dfs实现(染色默认染成1和2)。
Attention:无法使用两种颜色为奇数顶点个数的图染色。
【代码】
#include <bits/stdc++.h>
using namespace std;
const int N=100010,M=200010;
int h[N],e[M],ne[M],idx;
int n,m;
int color[N];
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;//将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;
for(int i=1;i<=n;i++){
if(!color[i]){//没有被染色
if(!dfs(i,1)){//将其染色
flag=false;
}
}
}
if(flag) puts("Yes");
else puts("No");
}
【小知识】
匹配:在图论中,一个 “ 匹配 ” 是一个边的集合,其中任意两条边都没有公共顶点。
最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。
完美匹配:如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。
交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边…形成的路径叫交替路。
增广路:从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发的点不算),则这条交替 路称为增广路(agumenting path)。
匈牙利算法(Hungarian algorithm):图论中寻找最大匹配的算法,暂不考虑加权的最大匹配
【分析】
1.存图模板
int h[N],ne[N],e[N],idx;
//n1,n2分别是两个点集的点的个数
int n1,n2,m;
void add(int a,int b){
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
//存边只存一边就行了,虽然是无向图,但是只需要遍历一边。
for(int i=0 ; i<n1;i++){
int a,b;
cin>>a>>b;
add(a,b);
}
2.一个找对象的过程
If the girl you want already has a boyfirend,then ask her boyfirend whether he could find another girl and leave this one for you !
TIP: 因为你要去问的都是男孩子,所以存边的时候,都是由男孩子指向女孩子
【代码】
#include <bits/stdc++.h>
using namespace std;
const int N=510,M=1e5+10;
int h[N],e[M],ne[M],idx;
bool st[N];
int match[N];//某点对应的boyfriend
int n1,n2,m;
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]==0||find(match[j])){//还没有boyfriend或者boyfriend有second choice
match[j]=x;
return true;//脱单
}
}
}
return false;
}
int main(){
memset(h,-1,sizeof h);
cin>>n1>>n2>>m;
while(m--){
int a,b;
cin>>a>>b;
add(a,b);
}
int res=0;//最大匹配数
for(int i=1;i<=n1;i++){
memset(st,false,sizeof st);//初始化每一个都没有
if(find(i)) res++;
}
cout<<res;
return 0;
}