利用KM算法求解最大权匹配
目录
前言
KM
算法是一种计算机算法,功能是求完备匹配下的最大权匹配。在一个二分图内,左顶点为X
,右顶点为Y
,现对于每组左右连接Xi->Yj
有权wij
,求一种匹配使得所有wij
的和最大
参考博客:KM算法入门
算法实现
题目背景
题解
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 305;
const int INF = 0x3f3f3f3f;
int love[MAXN][MAXN];
int ex_user[MAXN];
int ex_house[MAXN];
bool vis_user[MAXN];
bool vis_house[MAXN];
int match[MAXN];
int slack[MAXN];
int N;
bool dfs(int user) {
vis_user[user] = true;
for (int house = 0; house < N; ++house) {
if (vis_house[house]) continue;
int gap = ex_user[user] + ex_house[house] - love[user][house];
if (gap == 0) {
vis_house[house] = true;
if (match[house] == -1 || dfs(match[house])) {
match[house] = user;
return true;
}
} else {
slack[house] = min(slack[house], gap);
}
}
return false;
}
int KM() {
memset(match, -1, sizeof match);
memset(ex_house, 0, sizeof ex_house);
for (int i = 0; i < N; ++i) {
ex_user[i] = love[i][0];
for (int j = 1; j < N; ++j) {
ex_user[i] = max(ex_user[i], love[i][j]);
}
}
for (int i = 0; i < N; ++i) {
fill(slack, slack + N, INF);
//如果为用户 i 匹配房子失败 则通过降低期望值进行尝试匹配
while (1) {
memset(vis_user, false, sizeof vis_user);
memset(vis_house, false, sizeof vis_house);
// 如果为用户 i 匹配房子成功
if (dfs(i)) break;
int d = INF;
for (int j = 0; j < N; ++j)
if (!vis_house[j]) d = min(d, slack[j]);
for (int j = 0; j < N; ++j) {
if (vis_user[j]) ex_user[j] -= d;
if (vis_house[j])
ex_house[j] += d;
else
slack[j] -= d;
}
}
}
int res = 0;
for (int i = 0; i < N; ++i) res += love[match[i]][i];
return res;
}
int main() {
while (~scanf("%d", &N)) {
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j) scanf("%d", &love[i][j]);
printf("%d\n", KM());
}
return 0;
}
本文由「黄阿信」创作,创作不易,请多支持。
如果您觉得本文写得不错,那就点一下「赞赏」请我喝杯咖啡~
商业转载请联系作者获得授权,非商业转载请附上原文出处及本链接。
关注公众号,获取最新动态!
历史评论
开始评论