FROM THE NOTEBOOK
匈牙利算法
匈牙利算法主要被用于解决一些与二分图匹配有关的问题。
二分图#
二分图是一类特殊的图,它可以被划分为两个部分,每个部分的点互不相连,如下如图所示:
这样就是一个典型的二分图,可以看见,每条边的端点都分别处于左侧集合与右侧集合中。
最大匹配问题#
形式化的问题可能会比较抽象,我们用一个经典的例子来引入:
这个二分图,我们可以视为男生与女生的两个集合,边表示他们之间可能互相比较对眼。
最大匹配问题可以被视为:如果他们去参加一个舞会,舞会要求必须一男一女搭配(舞伴当然是从对眼的人里面选择了),这个时候,你最多能找出多少对舞伴?
算法过程#
显然,我们可以肉眼看出,最多能找出来3对,但对于复杂一些的图来说,我们就没办法一眼看出来了,这个时候我们来看看匈牙利算法是怎么运行的。
首先,我们从
然后我们观察
我们倒回去看
接着到
我们绕了这么大一圈发现,我们没办法改变其他人的配对对象了,那么
这就是匈牙利算法的流程了。
代码实现#
const int N = 505;
int m, n; //m,n 分别表示左、右侧集合的元素数量
int graph[N][N]; //邻接矩阵存图
int p[N];
bool vis[N];
bool match(int i){
for (int j = 1; j <= n; ++j)
if (graph[i][j] && !vis[j]) { // 有边存在且 j 未被访问过
vis[j] = true;
if (p[j] == 0 || match(p[j])) { // 如果暂无匹配对象 || 原来匹配的左侧对象可以找到新的匹配
p[j] = i; // 当前左侧元素成为当前右侧元素的新匹配
return true;
}
}
return false;
}
int Hungarian(){
int cnt = 0;
for (int i = 1; i <= M; ++i){
memset(vis, 0, sizeof(vis));
if (match(i))
cnt++;
}
return cnt;
}
算法复杂度#
可以发现,匈牙利算法以顶点集合 dfs 来搜索边集





讨论
想法、补充,或只是打个招呼。