概念:完全二分图G(X∪Y,X×Y)的最大权和匹配;
ps:若集合X和集合Y不是完全二分图或集合X和集合Y的顶点个数不相等,可构造0权值的边或产生0权值的顶点;
Kuhn-Munkres算法流程:
(1)初始化可行顶标的值;
(2)用匈牙利算法寻找完备匹配;
(3)若未找到完备匹配则修改可行顶标的值;
(4)重复(2)(3)直到找到相等子图的完备匹配为止。
时间复杂度:朴素实现O(n^4),不过通过加入松弛量可以做到O(n^3)
代码:(O(n^3))
const int N = 20, inf = 2147483647;
int w[N][N], match[N], visx[N], visy[N], lack;
int lx[N] = {0}, ly[N] = {0}; //顶标
bool dfs(int x)
{
visx[x] = true;
for (int y = 0; y < N; ++y)
{
if (visy[y]) continue;
int t = lx[x] + ly[y] - w[x][y];
if (t==0)
{
visy[y] = true;
if (match[y]==-1 || dfs(match[y]))
{
linky[y] = x;
return true;
}
}
else
lack = min(lack, t);
}
return false;
}
int km()
{
memset(match, -1, sizeof(match));
for (int i = 0; i < N; ++i)
for (int j = 0; j < N; ++j)
lx[i] = max(lx[i], w[i][j]); //初始化顶标
for (int x = 0; x < N; ++x)
{
for (; ;)
{
memset(visx, 0, sizeof(visx));
memset(visy, 0, sizeof(visy));
lack = inf;
if (dfs(x)) break;
for (int i = 0; i < N; ++i)
{
if (visx[i]) lx[i] -= lack;
if (visy[i]) ly[i] += lack;
}
}
}
int res = 0;
for (int j = 0; j < N; ++j)
if(match[j]>-1)
res += w[match[j]][j];
return res;
}