【每日算法】基础算法——二分图的最大匹配(五十三)

题目内容

给定一个二分图,其中左半部包含n1个点(编号1~n1),右半部包含n2个点(编号1~n2),二分图共包含m条边。

数据保证任意一条边的两个端点都不可能在同一部分中。

请你求出二分图的最大匹配数。

*二分图的匹配:给定一个二分图G,在G的一个子图M中,M的边集{E}中的任意两条边都不依附于同一个顶点,则称M是一个匹配。

二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。*

输入格式

第一行包含三个整数 n1、 n2 和 m。

接下来m行,每行包含两个整数u和v,表示左半部点集中的点u和右半部点集中的点v之间存在一条边。

输出格式

输出一个整数,表示二分图的最大匹配数。

数据范围

1≤n1,n2≤500 ,
1≤u≤n1,
1≤v≤n2,
1≤m≤10^5

输入样例

2 2 4
1 1
1 2
2 1
2 2

输出样例

2

题解

匈牙利算法是一种在多项式时间内求解任务分配问题的组合优化算法,并推动了后来的原始对偶方法。通过寻找增广路径,把增广路径中的匹配边和非匹配边的相互交换,这样就会多出一条匹配边,直到找不到增广路径为止。
具体理解可见这里

代码

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 510, M = 100010;

int n1,n2,m;
int h[N],e[M],ne[M],idx;
int match[N];
bool st[N];

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(){
scanf("%d%d%d", &n1, &n2, &m);

memset(h,-1,sizeof h);

while(m--){
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
}

int res = 0;
for(int i = 1; i<= n1; i++){
memset(st,false,sizeof st);
if(find(i)) res++;
}

printf("%d\n", res);

return 0;
}
Author: Frederic Niu
Link: https://www.fredericniu.cn/2021/01/28/【每日算法】基础算法——二分图的最大匹配(五十三)/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
我的公众号