步骤1 – 翻译:将以下关于"Maximum Bipartite Matching – GeeksforGeeks"的英文技术文章翻译成中文。
在二分图中,匹配是指这样一组边,其中任意两条边都没有公共端点。最大匹配是指具有最大尺寸(即边数最多)的匹配。在最大匹配中,如果再添加任何一条边,它就不再是匹配了。对于给定的二分图,可能存在不止一种最大匹配方案。
为什么我们要关注它?
许多现实世界的问题都可以转化为二分图匹配问题。例如,考虑下面这个问题:
“有 M 名求职者和 N 份工作。每名求职者都有自己感兴趣的工作子集。每个职位空缺只能接受一名求职者,而一名求职者也只能被任命担任一份工作。请找到一种工作分配方案,使得尽可能多的求职者获得工作。”
!<a href="https://media.geeksforgeeks.org/wp-content/cdn-uploads/maximummatching1.png">maximummatching1
我们强烈建议您先阅读以下文章:“最大流问题的 Ford-Fulkerson 算法”
最大二分图匹配与最大流问题:
最大二分图匹配 (MBP) 问题可以通过将其转化为流网络来解决(请观看此视频以了解我们是如何得出这一结论的)。具体步骤如下。
!<a href="https://media.geeksforgeeks.org/wp-content/cdn-uploads/maximummatching2.png">maximummatching2
1) 构建流网络:流网络必须有一个源和一个汇。因此,我们添加一个源,并添加从源到所有求职者的边。同样,添加从所有工作到汇的边。每条边的容量被标记为 1 个单位。
!<a href="https://media.geeksforgeeks.org/wp-content/cdn-uploads/maximummatching21.png">maximummatching2
2) 寻找最大流:我们使用 Ford-Fulkerson 算法在步骤 1 中构建的流网络中寻找最大流。最大流实际上就是我们寻找的 MBP。
如何实现上述方法?
让我们首先定义输入和输出形式。输入采用 Edmonds 矩阵的形式,它是一个二维数组 ‘bpGraph[M][N]‘,包含 M 行(代表 M 名求职者)和 N 列(代表 N 份工作)。如果第 i 名求职者对第 j 份工作感兴趣,则 bpGraph[i][j] 的值为 1,否则为 0。
输出是能够获得工作的最大人数。
实现这一点的一种简单方法是创建一个矩阵,表示具有 M+N+2 个顶点的有向图的邻接矩阵表示法。对该矩阵调用 fordFulkerson()。这种实现需要 O((M+N)*(M+N)) 的额外空间。
利用图是二分图且每条边的容量要么是 0 要么是 1 这一事实,可以减少额外空间并简化代码。其核心思想是使用 DFS 遍历为求职者寻找工作(类似于 Ford-Fulkerson 中的增广路径)。我们对每一名求职者调用 bpm(),bpm() 是基于 DFS 的函数,它会尝试所有可能性的分配工作给该求职者。
在 bpm() 中,我们会逐一尝试求职者 ‘u‘ 感兴趣的每一份工作,直到找到一份工作,或者尝试了所有工作但运气不佳。对于我们尝试的每一份工作,我们执行以下操作。
如果一份工作没有分配给任何人,我们 simply 将其分配给该求职者并返回 true。如果一份工作已经分配给了其他人,比如说 x,那么我们会递归地检查 x 是否可以分配其他工作。为了确保 x 不会再次获得相同的工作,我们在对 x 进行递归调用之前将工作 ‘v‘ 标记为“已见”(seen)。如果 x 可以获得其他工作,我们就更改工作 ‘v‘ 的求职者并返回 true。我们使用一个数组 maxR[0..N-1] 来存储分配给不同工作的求职者。
如果 bmp() 返回 true,这意味着流网络中存在一条增广路径,并且在 maxBPM() 的结果中添加了 1 个单位的流量。
C++
“
// A C++ program to find maximal
// Bipartite matching.
#include
#include
using namespace std;
// M is number of applicants
// and N is number of jobs
#define M 6
#define N 6
// A DFS based recursive function
// that returns true if a matching
// for vertex u is possible
bool bpm(bool bpGraph[M][N], int u,
bool seen[], int matchR[])
{
// Try every job one by one
for (int v = 0; v < N; v++)
{
// If appli