匈牙利算法
struct KM{ bool S[maxn], T[maxn]; int Lx[maxn], Ly[maxn]; int W[maxn][maxn]; int slack[maxn]; int myleft[maxn]; vector<int> G[maxn]; int n; void init(int n){ this -> n = n; for (int i = 0; i < n; i++) G[i].clear(); memset(W, 0, sizeof(W)); } void AddEdge(int u, int v, int val){ G[u].push_back(v); W[u][v] = val; } bool match(int u){ S[u] = true; int len = G[u].size(); for (int i = 0; i < len; i++){ int v = G[u][i]; if (!T[v]){ int a = Lx[u] + Ly[v] - W[u][v]; if (!a){ T[v] = true; if (myleft[v] == -1 || match(myleft[v])){ myleft[v] = u; return true; } } else slack[v] = min(slack[v], a); } } return false; } void update(){ int a = inf; for (int i = 0; i < n; i++) if (!T[i]) a = min(a, slack[i]); for (int i = 0; i < n; i++){ if (S[i]) Lx[i] -= a; if (T[i]) Ly[i] += a; else slack[i] -= a; } } void solve(){ for (int i = 0; i < n; i++){ Lx[i] = *max_element(W[i], W[i]+n); myleft[i] = -1; Ly[i] = 0; } for (int i = 0; i < n; i++){ for (int j = 0; j < n; j++) slack[j] = inf; while (true){ for (int j = 0; j < n; j++) S[j] = T[j] = 0; if (match(i)) break; else update(); } } } }