常用的二分图匹配算法是匈牙利算法,匈牙利算法的过程是,枚举每一个左部点 u ,然后枚举该左部点连出的边,对于一个出点 v,如果它没有被先前的左部点匹配,那么直接将 u 匹配 v,否则尝试让 v 的“原配”左部点去匹配其他右部点,如果“原配”匹配到了其他点,那么将 u 匹配 v,否则 u 失配。尝试让 “ 原配 ” 寻找其他匹配的过程可以递归进行。需要注意的是,在一轮递归中,每个右部点只能被访问一次。算法的时间复杂度为 O(n×e+m),其中 n 是左部点个数,e 是图的边数,m 是右部点个数。
匈牙利算法分女友版通俗易懂的讲解:
https://blog.youkuaiyun.com/Dark_Scope/article/details/8880547?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-3.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-3.control
因为这个解析,导致本人写的匹配数组都是girl[],OwO
模板题目洛谷P3386
https://www.luogu.com.cn/problem/P3386
题目描述
给定一个二分图,其左部点的个数为 n,右部点的个数为 m,边数为 e,求其最大匹配的边数。
左部点从 1 至 n 编号,右部点从 1 至 m 编号。
输入格式
输入的第一行是三个整数,分别代表 n,m 和 e。
接下来 e 行,每行两个整数 u,v,表示存在一条连接左部点 u 和右部点 v 的边。
输出格式
输出一行一个整数,代表二分图最大匹配的边数。
输入输出样例
输入 #1
1 1 1
1 1
输出 #1
1
输入 #2
4 2 7
3 1
1 2
3 2
1 1
4 2
4 1
1 1
输出 #2
2
说明/提示
数据规模与约定
对于全部的测试点,保证:
1≤n,m≤500。
1≤e≤5×104
1≤u≤n,1≤v≤m
不保证给出的图没有重边。
放上模板统计配对的数目输出即可:
#include<iostream>
#include<cstdio>
#include<memory.h>
using namespace std;
const int MAXN=550;
const int MAXM=550;
int n,m,e;
bool line[MAXN][MAXM],use[MAXM];
int girl[MAXM];
bool find(int x)
{
for(int i=1;i<=m;i++)
{
if (line[x][i]&&!use[i])
{
use[i]=true;
if (girl[i]==0||find(girl[i]))
{
girl[i]=x;
return true;
}
}
}
return false;
}
int main()
{
scanf("%d%d%d",&n,&m,&e);
for(int i=1,u,v;i<=e;i++)
{
scanf("%d%d",&u,&v);
line[u][v]=true;
}
int ans=0;
for(int i=1;i<=n;i++)
{
memset(use,false,sizeof(use));
if(find(i))
ans++;
}
printf("%d\n",ans);
return 0;
}
模板题2:洛谷P2319
链接:https://www.luogu.com.cn/problem/P2319
题目与第一题一样,除了数据范围不一样,有一点注意,当选手答错时要直接break掉,因为只有答对上一题才能继续往下继续答题。
AC代码:
#include<iostream>
#include<cstdio>
#include<memory.h>
using namespace std;
const int MAXN=1005;
const int MAXM=1005;
int n,m;
bool line[MAXM][MAXN],use[MAXN];
int girl[MAXN];
bool find(int x)
{
for(int i=0;i<n;i++)
{
if (line[x][i]&&!use[i])
{
use[i]=true;
if (girl[i]==0||find(girl[i]))
{
girl[i]=x;
return true;
}
}
}
return false;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,a,b;i<=m;i++)
{
scanf("%d%d",&a,&b);
line[i][a]=true;
line[i][b]=true;
}
int ans=0;
for(int i=1;i<=m;i++)
{
memset(use,false,sizeof(use));
if(find(i))
ans++;
else break;
}
printf("%d\n",ans);
return 0;
}