src/jiangly/graph/03-Max-Assignment.hpp
- View this file on GitHub
- Last update: 2025-02-17 23:08:47+08:00
- Include:
#include "src/jiangly/graph/03-Max-Assignment.hpp"
- Link: https://atcoder.jp/contests/abc247/submissions/30867023
- Link: https://qoj.ac/submission/184824
Code
/** 二分图最大权匹配(MaxAssignment 基于KM)
* 2022-04-10: https://atcoder.jp/contests/abc247/submissions/30867023
* 2023-09-21: https://qoj.ac/submission/184824
**/
constexpr int inf = 1E7;
template<class T>
struct MaxAssignment {
public:
T solve(int nx, int ny, std::vector<std::vector<T>> a) {
assert(0 <= nx && nx <= ny);
assert(int(a.size()) == nx);
for (int i = 0; i < nx; ++i) {
assert(int(a[i].size()) == ny);
for (auto x : a[i])
assert(x >= 0);
}
auto update = [&](int x) {
for (int y = 0; y < ny; ++y) {
if (lx[x] + ly[y] - a[x][y] < slack[y]) {
slack[y] = lx[x] + ly[y] - a[x][y];
slackx[y] = x;
}
}
};
costs.resize(nx + 1);
costs[0] = 0;
lx.assign(nx, std::numeric_limits<T>::max());
ly.assign(ny, 0);
xy.assign(nx, -1);
yx.assign(ny, -1);
slackx.resize(ny);
for (int cur = 0; cur < nx; ++cur) {
std::queue<int> que;
visx.assign(nx, false);
visy.assign(ny, false);
slack.assign(ny, std::numeric_limits<T>::max());
p.assign(nx, -1);
for (int x = 0; x < nx; ++x) {
if (xy[x] == -1) {
que.push(x);
visx[x] = true;
update(x);
}
}
int ex, ey;
bool found = false;
while (!found) {
while (!que.empty() && !found) {
auto x = que.front();
que.pop();
for (int y = 0; y < ny; ++y) {
if (a[x][y] == lx[x] + ly[y] && !visy[y]) {
if (yx[y] == -1) {
ex = x;
ey = y;
found = true;
break;
}
que.push(yx[y]);
p[yx[y]] = x;
visy[y] = visx[yx[y]] = true;
update(yx[y]);
}
}
}
if (found)
break;
T delta = std::numeric_limits<T>::max();
for (int y = 0; y < ny; ++y)
if (!visy[y])
delta = std::min(delta, slack[y]);
for (int x = 0; x < nx; ++x)
if (visx[x])
lx[x] -= delta;
for (int y = 0; y < ny; ++y) {
if (visy[y]) {
ly[y] += delta;
} else {
slack[y] -= delta;
}
}
for (int y = 0; y < ny; ++y) {
if (!visy[y] && slack[y] == 0) {
if (yx[y] == -1) {
ex = slackx[y];
ey = y;
found = true;
break;
}
que.push(yx[y]);
p[yx[y]] = slackx[y];
visy[y] = visx[yx[y]] = true;
update(yx[y]);
}
}
}
costs[cur + 1] = costs[cur];
for (int x = ex, y = ey, ty; x != -1; x = p[x], y = ty) {
costs[cur + 1] += a[x][y];
if (xy[x] != -1)
costs[cur + 1] -= a[x][xy[x]];
ty = xy[x];
xy[x] = y;
yx[y] = x;
}
}
return costs[nx];
}
std::vector<int> assignment() {
return xy;
}
std::pair<std::vector<T>, std::vector<T>> labels() {
return std::make_pair(lx, ly);
}
std::vector<T> weights() {
return costs;
}
private:
std::vector<T> lx, ly, slack, costs;
std::vector<int> xy, yx, p, slackx;
std::vector<bool> visx, visy;
};
#line 1 "src/jiangly/graph/03-Max-Assignment.hpp"
/** 二分图最大权匹配(MaxAssignment 基于KM)
* 2022-04-10: https://atcoder.jp/contests/abc247/submissions/30867023
* 2023-09-21: https://qoj.ac/submission/184824
**/
constexpr int inf = 1E7;
template<class T>
struct MaxAssignment {
public:
T solve(int nx, int ny, std::vector<std::vector<T>> a) {
assert(0 <= nx && nx <= ny);
assert(int(a.size()) == nx);
for (int i = 0; i < nx; ++i) {
assert(int(a[i].size()) == ny);
for (auto x : a[i])
assert(x >= 0);
}
auto update = [&](int x) {
for (int y = 0; y < ny; ++y) {
if (lx[x] + ly[y] - a[x][y] < slack[y]) {
slack[y] = lx[x] + ly[y] - a[x][y];
slackx[y] = x;
}
}
};
costs.resize(nx + 1);
costs[0] = 0;
lx.assign(nx, std::numeric_limits<T>::max());
ly.assign(ny, 0);
xy.assign(nx, -1);
yx.assign(ny, -1);
slackx.resize(ny);
for (int cur = 0; cur < nx; ++cur) {
std::queue<int> que;
visx.assign(nx, false);
visy.assign(ny, false);
slack.assign(ny, std::numeric_limits<T>::max());
p.assign(nx, -1);
for (int x = 0; x < nx; ++x) {
if (xy[x] == -1) {
que.push(x);
visx[x] = true;
update(x);
}
}
int ex, ey;
bool found = false;
while (!found) {
while (!que.empty() && !found) {
auto x = que.front();
que.pop();
for (int y = 0; y < ny; ++y) {
if (a[x][y] == lx[x] + ly[y] && !visy[y]) {
if (yx[y] == -1) {
ex = x;
ey = y;
found = true;
break;
}
que.push(yx[y]);
p[yx[y]] = x;
visy[y] = visx[yx[y]] = true;
update(yx[y]);
}
}
}
if (found)
break;
T delta = std::numeric_limits<T>::max();
for (int y = 0; y < ny; ++y)
if (!visy[y])
delta = std::min(delta, slack[y]);
for (int x = 0; x < nx; ++x)
if (visx[x])
lx[x] -= delta;
for (int y = 0; y < ny; ++y) {
if (visy[y]) {
ly[y] += delta;
} else {
slack[y] -= delta;
}
}
for (int y = 0; y < ny; ++y) {
if (!visy[y] && slack[y] == 0) {
if (yx[y] == -1) {
ex = slackx[y];
ey = y;
found = true;
break;
}
que.push(yx[y]);
p[yx[y]] = slackx[y];
visy[y] = visx[yx[y]] = true;
update(yx[y]);
}
}
}
costs[cur + 1] = costs[cur];
for (int x = ex, y = ey, ty; x != -1; x = p[x], y = ty) {
costs[cur + 1] += a[x][y];
if (xy[x] != -1)
costs[cur + 1] -= a[x][xy[x]];
ty = xy[x];
xy[x] = y;
yx[y] = x;
}
}
return costs[nx];
}
std::vector<int> assignment() {
return xy;
}
std::pair<std::vector<T>, std::vector<T>> labels() {
return std::make_pair(lx, ly);
}
std::vector<T> weights() {
return costs;
}
private:
std::vector<T> lx, ly, slack, costs;
std::vector<int> xy, yx, p, slackx;
std::vector<bool> visx, visy;
};