아래는 널리 검증된 표준 참조 구현(UOJ #79 계열)이다. 매우 미묘하므로 그대로 사용하기를 권한다. 정점은 1-인덱스, g[u][v].w에 가중치(간선 없으면 0). 반환은 최대 가중치 합.
#include <bits/stdc++.h>
using namespace std;
const int INF = 1e9, MAXN = 505;
struct E { int u, v, w; };
int n, n_x;
E g[MAXN][MAXN];
int lab[MAXN], match_[MAXN], slack[MAXN], st[MAXN], pa[MAXN];
int flower_from[MAXN][MAXN], S[MAXN], vis[MAXN];
vector<int> flower[MAXN];
deque<int> q;
int e_delta(const E& e) { return lab[e.u] + lab[e.v] - g[e.u][e.v].w * 2; }
void update_slack(int u, int x) { if (!slack[x] || e_delta(g[u][x]) < e_delta(g[slack[x]][x])) slack[x] = u; }
void set_slack(int x) { slack[x] = 0; for (int u = 1; u <= n; u++) if (g[u][x].w > 0 && st[u] != x && S[st[u]] == 0) update_slack(u, x); }
void q_push(int x) { if (x <= n) q.push_back(x); else for (int f : flower[x]) q_push(f); }
void set_st(int x, int b) { st[x] = b; if (x > n) for (int f : flower[x]) set_st(f, b); }
int get_pr(int b, int xr) {
int pr = find(flower[b].begin(), flower[b].end(), xr) - flower[b].begin();
if (pr % 2 == 1) { reverse(flower[b].begin() + 1, flower[b].end()); return (int)flower[b].size() - pr; }
return pr;
}
void set_match(int u, int v) {
match_[u] = g[u][v].v;
if (u > n) { E e = g[u][v]; int xr = flower_from[u][e.u], pr = get_pr(u, xr);
for (int i = 0; i < pr; i++) set_match(flower[u][i], flower[u][i ^ 1]);
set_match(xr, v); rotate(flower[u].begin(), flower[u].begin() + pr, flower[u].end()); }
}
void augment(int u, int v) { while (true) { int xnv = st[match_[u]]; set_match(u, v); if (!xnv) return;
set_match(xnv, st[pa[xnv]]); u = st[pa[xnv]]; v = xnv; } }
int get_lca(int u, int v) { static int t = 0; for (++t; u || v; swap(u, v)) { if (u == 0) continue;
if (vis[u] == t) return u; vis[u] = t; u = st[match_[u]]; if (u) u = st[pa[u]]; } return 0; }
void add_blossom(int u, int lca, int v) {
int b = n + 1; while (b <= n_x && st[b]) ++b; if (b > n_x) ++n_x;
lab[b] = 0; S[b] = 0; match_[b] = match_[lca]; flower[b].clear(); flower[b].push_back(lca);
for (int x = u, y; x != lca; x = st[pa[y]]) { flower[b].push_back(x); flower[b].push_back(y = st[match_[x]]); q_push(y); }
reverse(flower[b].begin() + 1, flower[b].end());
for (int x = v, y; x != lca; x = st[pa[y]]) { flower[b].push_back(x); flower[b].push_back(y = st[match_[x]]); q_push(y); }
set_st(b, b);
for (int x = 1; x <= n_x; x++) g[b][x].w = g[x][b].w = 0;
for (int x = 1; x <= n; x++) flower_from[b][x] = 0;
for (int f : flower[b]) {
for (int x = 1; x <= n_x; x++)
if (g[b][x].w == 0 || e_delta(g[f][x]) < e_delta(g[b][x])) g[b][x] = g[f][x], g[x][b] = g[x][f];
for (int x = 1; x <= n; x++) if (flower_from[f][x]) flower_from[b][x] = f;
}
set_slack(b);
}
void expand_blossom(int b) {
for (int f : flower[b]) set_st(f, f);
int xr = flower_from[b][g[b][pa[b]].u], pr = get_pr(b, xr);
for (int i = 0; i < pr; i += 2) { int xs = flower[b][i], xns = flower[b][i + 1];
pa[xs] = g[xns][xs].u; S[xs] = 1; S[xns] = 0; slack[xs] = 0; set_slack(xns); q_push(xns); }
S[xr] = 1; pa[xr] = pa[b];
for (int i = pr + 1; i < (int)flower[b].size(); i++) { int xs = flower[b][i]; S[xs] = -1; set_slack(xs); }
st[b] = 0;
}
bool on_found_edge(const E& e) {
int u = st[e.u], v = st[e.v];
if (S[v] == -1) { pa[v] = e.u; S[v] = 1; int nu = st[match_[v]]; slack[v] = slack[nu] = 0; S[nu] = 0; q_push(nu); }
else if (S[v] == 0) { int lca = get_lca(u, v);
if (!lca) { augment(u, v); augment(v, u); return true; } else add_blossom(u, lca, v); }
return false;
}
bool matching() {
fill(S + 1, S + n_x + 1, -1); fill(slack + 1, slack + n_x + 1, 0); q.clear();
for (int x = 1; x <= n_x; x++) if (st[x] == x && !match_[x]) { pa[x] = 0; S[x] = 0; q_push(x); }
if (q.empty()) return false;
while (true) {
while (!q.empty()) { int u = q.front(); q.pop_front(); if (S[st[u]] == 1) continue;
for (int v = 1; v <= n; v++) if (g[u][v].w > 0 && st[u] != st[v]) {
if (e_delta(g[u][v]) == 0) { if (on_found_edge(g[u][v])) return true; }
else update_slack(u, st[v]); } }
int d = INF;
for (int b = n + 1; b <= n_x; b++) if (st[b] == b && S[b] == 1) d = min(d, lab[b] / 2);
for (int x = 1; x <= n_x; x++) if (st[x] == x && slack[x]) {
if (S[x] == -1) d = min(d, e_delta(g[slack[x]][x]));
else if (S[x] == 0) d = min(d, e_delta(g[slack[x]][x]) / 2); }
for (int u = 1; u <= n; u++) { if (S[st[u]] == 0) { if (lab[u] <= d) return false; lab[u] -= d; }
else if (S[st[u]] == 1) lab[u] += d; }
for (int b = n + 1; b <= n_x; b++) if (st[b] == b) { if (S[b] == 0) lab[b] += d * 2; else if (S[b] == 1) lab[b] -= d * 2; }
q.clear();
for (int x = 1; x <= n_x; x++) if (st[x] == x && slack[x] && st[slack[x]] != x && e_delta(g[slack[x]][x]) == 0)
if (on_found_edge(g[slack[x]][x])) return true;
for (int b = n + 1; b <= n_x; b++) if (st[b] == b && S[b] == 1 && lab[b] == 0) expand_blossom(b);
}
return false;
}
long long solve() {
fill(match_ + 1, match_ + n + 1, 0); n_x = n; int wmax = 0;
for (int u = 1; u <= n; u++) { st[u] = u; flower[u].clear(); }
for (int u = 1; u <= n; u++) for (int v = 1; v <= n; v++) {
flower_from[u][v] = (u == v ? u : 0); wmax = max(wmax, g[u][v].w); }
for (int u = 1; u <= n; u++) lab[u] = wmax; // 쌍대 초기화
while (matching()) {} // 증가 경로가 없을 때까지
long long tot = 0;
for (int u = 1; u <= n; u++) if (match_[u] && match_[u] < u) tot += g[u][match_[u]].w;
return tot;
}