这是一个非常简单的问题,描述如下,给你两部分的点,问你最大匹配数是多少、
- 简单描述一下算法流程,首先我们先匹配左边,蓝1先匹配红2;接下来到蓝2,只能匹配红2,但是这这时候发现红2已经有主了,根据匈牙利算法思想,这时候回溯,找谁匹配的红2,发现是蓝1,那么这时候看看蓝1还有没有别的选择,一看可以是红4,所以这时候让蓝1匹配红4,蓝2匹配红2;之后是蓝3,先让他匹配红1,没矛盾;现在得到的二分图如下所示
- 那么现在轮到蓝4了,他只能跟红4匹配,但是红4已经有主了,这时候回溯看蓝1,他还有一个选择是红2,但是红2也有主了,这时候回溯看蓝2,他没别的选择,所以全部返回 f a l s e false false,蓝4失配,所以最大匹配是3
上述过程实际上是在找一条从一个左边未匹配点到右边一个未匹配点的增广路径,上面并未介绍任何术语,因为二分图最大匹配问题是一个简单的问题,算法流程是很自然的
- 因为算法最坏情况所构造的每个顶点的增广路可能会经过所有的边,所以算法时间复杂度是 O ( V E ) O(VE) O(VE)的,比较优秀
例题
https://www.luogu.com.cn/problem/P3386
模板
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int n, m, e;
cin >> n >> m >> e;
vector<vector<int> > g(n);
while(e--){
int u, v;
cin >> u >> v;
u -= 1;
v -= 1;
g[u].push_back(v);
}
vector<int> match(m, -1);
int ans = 0;
for(int i=0;i<n;i++){
vector<int> vis(m);
function<bool(int)> Dfs = [&](int u){
for(auto i : g[u]){
if(!vis[i]){
vis[i] = 1;
if(match[i] == -1 || Dfs(match[i])){
match[i] = u;
return true;
}
}
}
return false;
};
if(Dfs(i)) ans += 1;
}
cout << ans;
return 0;
}
http://acm.hdu.edu.cn/showproblem.php?pid=2063
也是模板
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int k, m, n;
while(cin >> k){
if(k == 0) break;
cin >> m >> n;
vector<vector<int> > g(m);
for(int i=0;i<k;i++){
int u, v;
cin >> u >> v;
u -= 1;
v -= 1;
g[u].push_back(v);
}
int ans = 0;
vector<int> match(n, -1);
for(int i=0;i<m;i++){
vector<int> vis(n);
function<bool(int)> Dfs = [&](int u){
for(auto v : g[u]){
if(!vis[v]){
vis[v] = 1;
if(match[v] == -1 || Dfs(match[v])){
match[v] = u;
return true;
}
}
}
return false;
};
if(Dfs(i)) ans += 1;
}
cout << ans << '\n';
}
return 0;
}
https://www.luogu.com.cn/problem/P1129
- 二分图匹配重要的在于建模能力,能不能看出来问题的本质。比如上面这个问题,它是一个二分图匹配的问题,为什么?
- 问题描述很简单,一个 n × n n\times n n×n的矩阵,可以交换某两列或者某两行,问能不能让主对角线上元素都是1
- 我们要进行一个思维转换,如果 a [ i ] [ j ] = 1 a[i][j]=1 a[i][j]=1,我们称 i , j i,j i,j构成一种对应关系,根据二分图思想,我们枚举第 i i i行,如果能找到最大匹配数是 n n n,那么是不是我们就可以进行某些移动来达到主对角线上元素都是1的目的了呢?因为二分图的两边各自都是 n n n个不同的数字
- 进行这样的思维转换,能够发现这是一道匈牙利算法的裸题
#include <bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin >> t;
while(t--){
int n;
cin >> n;
vector<vector<int> > a(n, vector<int>(n));
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
cin >> a[i][j];
}
}
int ans = 0;
vector<int> match(n, -1);
for(int i=0;i<n;i++){
vector<int> vis(n);
function<bool(int)> Dfs = [&](int u){
for(int i=0;i<n;i++){
if(!vis[i] && a[u][i] == 1){
vis[i] = 1;
if(match[i] == -1 || Dfs(match[i])){
match[i] = u;
return true;
}
}
}
return false;
};
if(Dfs(i)) ans += 1;
}
cout << (ans == n ? "Yes" : "No") << '\n';
}
return 0;
}