文章目录
1 二分图相关概念
二分图定义:
二分图又称双分图、二部图、偶图,指顶点可以分成两个不相交的集U和V(U和V皆为独立集(Independent Sets)),使得在同一个集内的顶点不相邻(没有共同边)的图。




我们定义匹配点、匹配边、未匹配点、非匹配边。如图3中,1、4、5、7为匹配点,其他顶点为未匹配点;1-5、4-7为匹配边、其他边为非匹配边。
**匹配(matching)😗*二分图的一个“匹配”是指一些边的集合,任意两条边没有公共点。例如,图3、图4中红色的边就是图2的匹配。
**最大匹配(maximum matching):**二分图的“最大匹配”,值的是二分图的所有匹配中边数最多的匹配。图4是一个最大匹配。它包含4条匹配边。
**完美匹配(perfect matching):**二分图的一个“完美匹配”,是指所有点都在这个匹配中的一个匹配。也就是说这个匹配里的所有边刚好经过所有点一次。图4是一个完美匹配,显然,完美匹配一定是最大匹配(完美匹配的任何一个点都已经匹配,添加一条新的匹配边一定会与已有的匹配边冲突)。
但并非每个图都存在完美匹配。
2 匈牙利算法求解无权二分图最大匹配
2.1 相关概念

**交替路:**从一个未匹配点出发,依次经过非匹配边、匹配边、非匹配边…形成的路径叫交替路。
**增广路:**从一个未匹配点出发,走交替路,如果以另一个未匹配点(出发的点不算)为结尾,则这条交替路称为增广路(agumenting path)。例如,图 5 中的一条增广路如图 6 所示(图中的匹配点均用红色标出):

增广路有一个重要特点:非匹配边比匹配边多一条。因此,研究增广路的意义是改进匹配。只要把增广路中的匹配边和非匹配边的身份交换即可。由于中间的匹配节点不存在其他相连的匹配边,所以这样做不会破坏匹配的性质。交换后,图中的匹配边数目比原来多了 1 条。
我们可以通过不停地找增广路来增加匹配中的匹配边和匹配点。找不到增广路时,达到最大匹配(这是增广路定理)。匈牙利算法正是这么做的。
**增广路定理:**任意一个非最大匹配的匹配一定存在增广路。
匈牙利树一般由BFS构造(类似于BFS树)。从一个未匹配点出发运行BFS(唯一的限制是,必须走交替路),直到不能再扩展为止。例如,由图7,可以得到如图8的一棵 BFS 树:



这棵树存在一个叶子节点为非匹配点(7 号),但是匈牙利树要求所有叶子节点均为匹配点,因此这不是一棵匈牙利树。如果原图中根本不含 7 号节点,那么从 2 号节点出发就会得到一棵匈牙利树。这种情况如图 9 所示(顺便说一句,图 8 中根节点 2 到非匹配叶子节点 7 显然是一条增广路,沿这条增广路扩充后将得到一个完美匹配)。
2.2 算法原理
注意前面增广路的定义:“从一个未匹配点出发,走交替路,以另一个未匹配点为结尾”,首尾都是未匹配点,说明首尾的边都是非匹配边。而又是交替路,也就是说非匹配边比匹配边多一条。那么我们完全可以把这条增广路里的匹配边和非匹配边互换(称为“交换匹配”),那么匹配边就会多出 1 条,实现了“增广”的意义。并且这样做并不会对其他边造成影响,也不破坏二分图的性质。
那么我们就可以一直找增广路,不断交换匹配。根据增广路定理,如果找不到了,就说明已经达到最大匹配。
同样可以证明,已经匹配的点永远不会退出匹配,只会更换匹配。
这就是匈牙利算法最核心的部分了:一直找增广路,不断交换匹配。
可能看完上面的叙述,还是有点困惑。一直找增广路,不断交换匹配到底应该怎么做?以下我举一个便于理解例子:

现在Boys和Girls分别是两个点集,里面的点分别是男生和女生,边表示他们之间存在“暧昧关系”。最大匹配问题相当于,假如你是红娘,可以撮合任何一对有暧昧关系的男女,那么你最多能成全多少对情侣?(数学表述:在二分图中最多能找到多少条没有公共端点的边)
现在我们来看看匈牙利算法是怎么运作的:
我们从B1看起(男女平等,从女生这边看起也是可以的),他与G2有暧昧,那我们就先暂时把他与G2连接(注意这时只是你作为一个红娘在纸上构想,你没有真正行动,此时的安排都是暂时的)。

来看B2,B2也喜欢G2,这时G2已经“名花有主”了(虽然只是我们设想的),那怎么办呢?我们倒回去看G2目前被安排的男友,是B1,B1有没有别的选项呢?有,G4,G4还没有被安排,那我们就给B1安排上G4。

我们来细看这一过程:
开始是B1——G2;
由于B2的加入,有增广路G4——B1——G2——B2;
然后交换匹配,成为G4——B1——G2——B2;
这是不是正是前面提到的一直找增广路,不断交换匹配。
我们继续,B3直接配上G1就好了,这没什么问题。至于B4,他只钟情于G4,G4目前配的是B1。B1除了G4还可以选G2,但是呢,如果B1选了G2,G2的原配B2就没得选了。我们绕了一大圈,发现B4只能注定单身了,可怜。(其实从来没被考虑过的G3更可怜)
最终结果:

2.3 匈牙利算法代码
//---------------------DFS---------------------------------
#include<iostream>
#include<memory.h>
using namespace std;
#define MAXN 10
int graph[MAXN][MAXN];
int match[MAXN];
int visitX[MAXN], visitY[MAXN];
int nx, ny;
bool findPath( int u )
{
visitX[u] = 1;
for( int v=0; v<ny; v++ )
{
if( !visitY[v] && graph[u][v] )
{
visitY[v] = 1;
if( match[v] == -1 || findPath(match[v]) )
{
match[v] = u;
return true;
}
}
}
return false;
}
int dfsHungarian()
{

最低0.47元/天 解锁文章
6132





