KM算法是用来求完全二分图最大完美匹配的算法,其原理是不断寻找增广路(增广路定理)。相关性质:在最大二分图匹配图中,W[x][y] <= Lx[x] + Ly[y]。
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 2505;
const int INF = 0x3f3f3f3f;
int n, m;
int W[MAXN][MAXN];
int Lx[MAXN], Ly[MAXN];
int Left[MAXN];
bool S[MAXN], T[MAXN];
bool match(int i)
{
S[i] = true;
for (int j = 1; j <= m; j++)
{
if (Lx[i]+Ly[j] == W[i][j] && !T[j])
{
T[j] = true;
if (!Left[j] || match(Left[j]))
{
Left[j] = i;
return true;
}
}
}
return false;
}
void update()
{
int a = INF;
for (int i = 1; i <= n; i++)
{
if (!S[i]) continue;
for (int j = 1; j <= m; j++)
{
if (T[j]) continue;
a = min(a, Lx[i]+Ly[j]-W[i][j]);
}
}
for (int i = 1; i <= n; i++)
{
if (S[i]) Lx[i] -= a;
}
for (int j = 1; j <= m; j++)
{
if (T[j]) Ly[j] += a;
}
}
void KM()
{
memset(Left, 0, sizeof(Left));
memset(Ly, 0, sizeof(Ly));
for (int i = 1; i <= n; i++)
{
Lx[i] = -INF;
for (int j = 1;j <= n*m; j++)
Lx[i] = max(Lx[i], W[i][j]);
}
for (int i = 1; i <= n; i++)
{
for (;;)
{
memset(S, false, sizeof(S));
memset(T, false, sizeof(T));
if (match(i)) break;
else update();
}
}
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d%d", &n, &m);
memset(W, 0, sizeof(W));
KM();
}
return 0;
}