题目描述
给定一个二分图,其中左半部包含 个点(编号 ),右半部包含 个点(编号 ),二分图共包含 条边。
数据保证任意一条边的两个端点都不可能在同一部分中。
请你求出二分图的最大匹配数。
二分图的匹配:给定一个二分图 ,在 的一个子图 中, 的边集 {} 中的任意两条边都不依附于同一个顶点,则称 是一个匹配。
二分图的最大匹配:所有匹配中包含边数最多的一组匹配被称为二分图的最大匹配,其边数即为最大匹配数。
输入格式
第一行包含三个整数 、 和 。
接下来 行,每行包含两个整数 和 ,表示左半部点集中的点 和右半部点集中的点 之间存在一条边。
输出格式
输出一个整数,表示二分图的最大匹配数。
数据范围
,
,
,
输入样例:
2 2 4
1 1
1 2
2 1
2 2
输出样例:
2
题目分析
这是一道关于匈牙利算法下的二分图匹配的问题。
首先我们按左右将节点按题意分为两部分,以左边节点为起始节点开始考虑,如果其所连边中的右侧节点有未曾被匹配的节点,则将这两个节点作为匹配的一对,并对答案产生 的贡献。
在上述思想下,我们来考虑一个问题,即如何选择每个左节点的最优右节点匹配。假设左节点 都能与右节点 进行匹配,且只有左节点 能与右节点 匹配,那么最终匹配对应为 。若一开始我们将 作为匹配的一对,在考虑 的匹配时,便需要更改 的匹配以形成最优结果。
那么我们如何更改 的匹配呢,这时便需要从 的剩余可连节点中找寻未被匹配的 ,即用递归的方式进行查询。
在这里我们同时要引入 数组,在我看来,这个数组的作用是为了减少递归的层数,避免内存爆栈。
由于每个节点最多会对所有边进行一次遍历,所以时间复杂度为 。
Accept代码
#include <bits/stdc++.h>
using namespace std;
const int N = 510;
vector<int> g[N];
bool st[N];
int match[N];
bool find(int x)
{
for (auto y : g[x])
if (!st[y])
{
st[y] = true;
if (!match[y] || find(match[y]))
{
match[y] = x;
return true;
}
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n1, n2, m;
cin >> n1 >> n2 >> m;
while (m --)
{
int a, b;
cin >> a >> b;
g[a].push_back(b);
}
int res = 0;
for (int i = 1; i <= n1; i ++)
{
memset(st, 0, sizeof st);
if (find(i)) res ++;
}
cout << res;
return 0;
}