匈牙利算法
前导知识:
- 匹配:在图论中,一个「匹配」是一个边的集合,其中任意两条边都没有公共顶点。
- 最大匹配:一个图所有匹配中,所含匹配边数最多的匹配,称为这个图的最大匹配。
- 完美匹配:如果一个图的某个匹配中,所有的顶点都是匹配点,那么它就是一个完美匹配。
- 交替路:从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边…形成的路径叫交替路。
- 增广路:从一个未匹配点出发,走交替路,如果途径另一个未匹配点(出发的点不算),则这条交替 路称为增广路。
匈牙利算法思想:
给定两个集合:男生、女生
把男生和女生匹配起来。
如果后面的男生和前面的男生喜欢同一个女生,并且前面的男生还有其他心仪的女生,那么前面的男生就不追那个女生了,让后面的男生去追那个女生。
代码实现:
#include <iostream>
#include <cstring>
#include <algorithm>
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; i = ne[i])
{
int j = e[i]; // 妹子j
if (!st[j]) // 如果妹子还没有被考虑过
{
st[j] = true; // 妹子已经被一个男生看上了
if (!match[j] || 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 ++ ; // 结局很美满
}
cout << res << endl;
return 0;
}