Problem. workers, jobs, a cost matrix . Assign each worker to exactly one job minimising the total cost.
Equivalently: a minimum-cost perfect matching in a complete bipartite graph.
The methods
| Method | Time | Feasible |
|---|---|---|
| Brute force over permutations | 10 | |
| Bitmask DP | 20 | |
| Hungarian algorithm | 500-1000 | |
| Min-cost flow (SSP + potentials) | 500 | |
| Gabow-Tarjan scaling | theoretical | |
| Auction algorithm | parallelisable | |
| Greedy | not optimal |
Write the Hungarian algorithm for , bitmask DP below that.
Bitmask DP — the easy option
long long assignment(int n, vector<vector<long long>>& c) {
vector<long long> dp(1 << n, LLONG_MAX / 2);
dp[0] = 0;
for (int mask = 0; mask < (1 << n); mask++) {
int i = __builtin_popcount(mask); // next worker to assign
if (i == n || dp[mask] == LLONG_MAX / 2) continue;
for (int j = 0; j < n; j++)
if (!(mask >> j & 1))
dp[mask | (1 << j)] = min(dp[mask | (1 << j)], dp[mask] + c[i][j]);
}
return dp[(1 << n) - 1];
}Using popcount(mask) to derive the worker index removes an entire dimension. — instant for , and far easier to get right than Hungarian.
The Hungarian algorithm in one paragraph
Maintain dual potentials (workers) and (jobs) with . Edges achieving equality form the tight subgraph; grow an alternating tree in it, and when stuck, adjust the potentials by the minimum slack to expose new tight edges. Each of phases matches one more worker in , giving .
The invariant is LP duality: at the end equals the optimum, which is a certificate of optimality. See Hungarian Algorithm.
Variants
| Variant | Method |
|---|---|
| Maximise instead of minimise | negate the costs, or subtract from the maximum |
| Rectangular () | pad with zero-cost dummy rows or columns |
| Some assignments forbidden | set those costs to |
| Bottleneck assignment (minimise the max cost) | binary search + bipartite matching |
| Workers handle jobs | min-cost flow with capacities |
| Costs change over time | recompute, or use the incremental Hungarian |
| Non-bipartite (general graph) | weighted Blossom |
| Only feasibility (any perfect matching) | Hopcroft-Karp, |
| 3-dimensional assignment | NP-hard |
Bottleneck assignment is worth calling out: binary search the threshold , keep only edges with cost , and test for a perfect matching. and much simpler than a specialised algorithm — the standard “binary search + feasibility” pattern.
Why greedy fails
Assigning the globally cheapest pair, then the next, and so on, is not optimal:
Greedy takes then is forced into , total 101. The optimum is .
The failure is instructive: greedy has no way to account for the opportunity cost of a choice, which is exactly what the Hungarian algorithm’s dual potentials encode.
Recognising it
The assignment problem hides behind many phrasings:
- “match each person to a task minimising total time”,
- “pair up points to minimise total distance” (with two colour classes),
- “assign each row a distinct column with minimum penalty”,
- “select one element from each row, all in distinct columns”.
Whenever a problem needs a bijection between two sets of size with an additive cost, it is this problem.
Why it is worth knowing
It is the canonical example of a problem where:
- the naive greedy is wrong,
- the exponential search is unnecessary,
- and a polynomial algorithm exists via LP duality.
The dual potentials also reappear in min-cost flow and Johnson’s reweighting, so understanding them once pays off repeatedly.
See also: Hungarian Algorithm · Min-Cost Flow · Bitmask DP