二分图:将图的顶点划分为两个集合,集合里点之间是没有边连接的。
定理:当且仅当图中不含奇数环图是二分图。
1、860. 染色法判定二分图
思路:将一条边上的两个点染成两种不同的颜色。如果是二分图,由于图中不含奇数环,所以染色过程中一定没有矛盾。
#include<iostream>
#include<cstring>
using namespace std;
const int N=1e5+10;
int h[N],e[2*N],ne[2*N],idx;
int n,m,color[N];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
bool dfs(int u,int c)
{
color[u]=c;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!color[j])
{
if(!dfs(j,3-c))//3-c很妙,如果该点是染色为1,下一个点就为2,反之,也是
return false;
}
else if(color[j]==c)
return false;
}
return true;
}
int main()
{
memset(h,-1,sizeof(h));
cin>>n>>m;
int u,v;
for(int i=0;i<m;i++)
{
cin>>u>>v;
add(u,v),add(v,u);
}
bool flag=true;
for(int i=1;i<=n;i++)
{
if(!color[i])
{
if(!dfs(i,1))//染色失败,不是二分图
{
flag=false;
break;
}
}
}
if(flag) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
return 0;
}
2、匈牙利算法
861. 二分图的最大匹配
匈牙利算法,思想:遍历一边的点,遍历这个点的所有出边,如果出边所对的这个点还没有匹配过,就直接匹配成功,否则查找与这个点匹配的点是否还有其它点可以让它匹配(挖墙脚),有的话让它去匹配其他点,把这个点让给它。
#include<iostream>
#include<cstring>
using namespace std;
const int N=510,M=1e5+10;
int h[N],e[M],ne[M],idx;
int match[N];
bool st[N];
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]))//如果当前的这个点已匹配了,去查找与他匹配的点还有没有其他的点可以匹配的
{
match[j]=x;
return true;
}
}
}
return false;
}
int main()
{
memset(h,-1,sizeof(h));
cin>>n1>>n2>>m;
int u,v;
for(int i=0;i<m;i++)
{
cin>>u>>v;
add(u,v);//虽然无向图,但是由于只需要和另外一部分进行匹配,所以建一边的边就好了
}
int res=0;
for(int i=1;i<=n1;i++)
{
memset(st,false,sizeof(st));
if(find(i)) res++;
}
cout<<res<<endl;
return 0;
}