一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第22天,点击查看活动详情。
概念
匹配成功 :不存在两条边共用两个点 匈牙利算法返回匹配成功的最大数量是多少
例子
男女之间的恋爱关系,不存在脚踩两条船的情况
基本思路
不撞南墙不回头:每次匹配的时候,如果匹配到的点已经属于其他人了,那么就看一下那个"其他人"有没有备胎,能不能换一个
时间复杂度
最坏情况:O(n * m) ,n个男生,m个女生 但是很多少时候都会比这个小
题目
代码
#include <cstring>
#include <algorithm>
#include <iostream>
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]; // 判重,每次不要重复搜一个点
// 插入一条a指向b的边
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]; // 用j来表示当前点的编号
if (!st[j]) // 如果妹子之前没有被考虑过
{
st[j] = true;
if (match[j] == 0 || find(match[j])) // 如果妹子没有匹配过男生的话match == 0表示没有匹配男生,或者说虽然匹配了男生,但是可以为男生找到下家
{
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++; // 如果成功匹配到的话,结果res++
}
printf("%d\n", res);
return 0;
}