二分图的最大匹配
前面的博客已经介绍了什么是二分图,以及怎么用染色法判断一个图是不是二分图;
这里介绍二分图的匹配问题;
先说什么是匹配:
对于一个二分图G的子图M,若M的边集E的的任意两条边都不连接同一个顶点,则称M为G的一个匹配。
最大匹配:
对于二分图G的一个子图M,若M为其边数最多的子图,则称M为G的最大匹配。
匈牙利算法,复杂度为 O ( n ∗ e + m ) O(n*e+m) O(n∗e+m),n个左部点,m个右部点,e条边:
1.先建立一个有向图,我习惯于左边连向右边;
2.然后枚举左边的点,判断每个点是否可以连接一个右边的点,并且不产生冲突;
3.如果产生了冲突,看是否可以通过一定的方式化解这个冲突;比如左边的 a 连上了右边的 b,但是右边的 b 早已被左边的 c 所连,这样看来,a 是没办法连 b 了,但是这个算法的精髓就来了,我们可以看看 c 是否可以不连 b ,连其他的点,保证最大的匹配数;
其实还是一种贪心的思想;
代码:
#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define lson k<<1
#define rson k<<1|1
//ios::sync_with_stdio(false);
using namespace std;
const int N=1000100;
const int M=100100;
const LL mod=1e9+7;
int n1,n2,m;
struct Node{
int to,nex;
}edge[N];
int head[1100];
int cnt;
void add(int p,int q){
edge[cnt].to=q;
edge[cnt].nex=head[p];
head[p]=cnt++;
}
bool v[1100];//标记右半部分是否匹配
int fa[1100];//记录右半部分所匹配的左半部分是什么
bool find(int p){
for(int i=head[p];~i;i=edge[i].nex){
int q=edge[i].to;
if(!v[q]){
v[q]=true;
if(fa[q]==0||find(fa[q])){//跟并查集有点相似
fa[q]=p;
return true;
}
}
}
return false;
}
int main(){
ios::sync_with_stdio(false);
memset(head,-1,sizeof(head));
cin>>n1>>n2>>m;
for(int i=1;i<=m;i++){
int p,q;
cin>>p>>q;
if(p>n1||q>n2) continue;
add(p,q);
}
int s=0;
for(int i=1;i<=n1;i++){
memset(v,false,sizeof(v));
if(find(i)) s++;
}
cout<<s<<endl;
return 0;
}