二分图中的最大匹配数:从二分图中选择一些边(这些边连接集合A和集合B,集合A中结点数目为n1,集合B中结点数目为n2),设为集合S,其中任意两条边不共用一个结点。求集合S的最大元素数目,即二分图中的最大匹配数。
匈牙利算法的关键步骤:
bool find(int a) {//a为集合A中的结点
for (auto b : g[x]) {
if (!st[b]) {//如果结点b没有被访问
st[b] = true;
if (match[b] == 0 || find(match[b])) { //如果结点b没有被匹配,或者结点b匹配了的结点可以找到新的
match[b] = a;
return true;
}
}
}
return false;
}
int n1, n2; // n1表示第一个集合中的点数,n2表示第二个集合中的点数
int h[N], e[M], ne[M], idx; // 邻接表存储所有边,匈牙利算法中只会用到从第一个集合指向第二个集合的边,所以这里只用存一个方向的边
int match[N]; // 存储第二个集合中的每个点当前匹配的第一个集合中的点是哪个
bool st[N]; // 表示第二个集合中的每个点是否已经被遍历过
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 res = 0;
for (int i = 1; i <= n1; i ++ )
{
memset(st, false, sizeof st);
if (find(i)) res ++ ;
}
题目1:求二分图的最大匹配。
#include
#include
#include
using namespace std;
const int N = 510;
int n1, n2, m;
vector<vector<int>> g(N);
int match[N];
bool st[N];
bool find(int a) {
for (auto b : g[a]) {
if (!st[b]) {
st[b] = true;
if (match[b] == 0 || find(match[b])) {
match[b] = a;
return true;
}
}
}
return false;
}
int main() {
cin >> n1 >> n2 >> m;
int a, b;
while (m--) {
cin >> a >> b;
g[a].emplace_back(b);
}
int res = 0;
for (int i = 1; i <= n1; ++i) {
memset(st, 0, sizeof st);
if (find(i)) res++;
}
cout << res << endl;
return 0;
}