Graph Algorithms
Blossom Algorithm: Maximum Matching in General Graphs
In 1965 Jack Edmonds needed to pair up nodes in a graph so that as many edges as possible are used, with no node used twice. On bipartite graphs (two-colorable, no odd cycles) a simple augmenting-path search solves this. But throw in a single odd cycle — a triangle, a pentagon — and that search silently returns the wrong answer. Edmonds' Blossom Algorithm was the first to fix this, and in doing so it became one of the founding results of polynomial-time combinatorial optimization.
The Blossom Algorithm computes a maximum-cardinality matching in an arbitrary undirected graph in polynomial time. A matching is a set of edges with no shared endpoints; "maximum" means no matching has more edges. The algorithm's trick is to detect odd-length cycles (the "blossoms") that trap the search, contract each into a single super-vertex, recurse, and later expand the contraction to recover the real edges. Edmonds published it in "Paths, Trees, and Flowers," proving the problem is tractable — his paper is where the modern notion of "efficient = polynomial time" was crystallized.
- TypeGraph matching (combinatorial optimization)
- InventedJack Edmonds, 1965 ("Paths, Trees, and Flowers")
- Time complexityO(V^3) typical; O(E·V^2) naive; O(E·√V) best (Micali-Vazirani)
- SpaceO(V + E)
- Key ideaContract odd cycles (blossoms) into super-vertices, then augment
- Used inKidney-exchange, scheduling, chip layout, Christofides TSP, chemistry
Interactive visualization
Press play, or step through manually. The visualization is yours to drive — try it before reading on.
Watch the 60-second explainer
A condensed visual walkthrough — narrated, captioned, under a minute.
The problem: why odd cycles break simple matching
A matching M in a graph is a set of edges sharing no endpoints. Growing a matching relies on an augmenting path: a path that starts and ends at unmatched vertices and alternates unmatched, matched, unmatched edges. Flip every edge along it (matched becomes unmatched and vice versa) and the matching grows by exactly one. Berge's theorem guarantees a matching is maximum if and only if no augmenting path exists — so the whole game is finding augmenting paths.
In bipartite graphs a simple BFS/DFS finds them reliably, because alternating-path parity is unambiguous. In general graphs an odd cycle wrecks this. Consider a triangle where two edges must alternate around it: a vertex can be reached by both an even-length and an odd-length alternating walk simultaneously. The naive search commits to one parity, misses valid augmentations, and reports a matching that is too small.
- Bipartite: no odd cycles, parity is well-defined, augmenting search just works.
- General: odd cycles create parity ambiguity — the core difficulty Edmonds solved.
How it works: grow a forest, contract the blossom
The algorithm builds an alternating forest rooted at every exposed (unmatched) vertex. Vertices get parity labels: even (outer, reachable by an even-length alternating path from a root) and odd (inner). It scans edges from even vertices:
- Even → unlabeled matched vertex: extend the tree (add the vertex as odd, its match as even).
- Even → even in a different tree: an augmenting path is found — flip it, restart.
- Even → even in the same tree: a blossom — an odd cycle through the two vertices' lowest common ancestor.
find_augmenting_path(G, M):
forest = {exposed vertices as even roots}
while some even vertex v has an unscanned edge (v,w):
if w unlabeled: add w (odd) and match(w) (even) to forest
elif w is even, different tree: return path(v)+path(w) # augment
elif w is even, same tree: B = blossom(v,w)
contract B into super-vertex
recurse on contracted graph
return none # matching is maximum (Berge)Contracting the blossom into one super-vertex removes the parity ambiguity. When the recursion finds an augmenting path through the super-vertex, it is lifted back: expand the blossom and route the path around the correct side of the odd cycle.
Complexity and a worked trace
Each augmentation increases the matching by one, so there are at most V/2 augmentations. One search for an augmenting path — including finding and contracting blossoms — costs O(V·E) naively, giving O(V^2·E) or roughly O(V^4) for dense graphs (Edmonds' original bound). Using a labeling scheme that never physically shrinks the graph (Gabow 1976), a search runs in O(V^2) and the total drops to O(V^3), the common textbook and library bound. The theoretical champion is Micali-Vazirani (1980) at O(E·√V), which finds many shortest augmenting paths per phase. Space is O(V + E).
Trace on a triangle plus a pendant: vertices A-B-C form a triangle; D hangs off A. Start empty. Match B-C. Now A and D are exposed; root the forest at A. Edge A-B: B becomes odd, its match C becomes even. Edge C-A: both A and C are even in the same tree — blossom {A,B,C}. Contract to super-vertex S. Now S-D is an edge between two exposed vertices: augment. Lifting the blossom, the real augmenting path is D-A, and we route B-C untouched — final matching {D-A, B-C}, size 2, which is maximum.
Where it is used in real systems
General-graph matching appears wherever pairings are symmetric (unlike bipartite job-to-worker assignment):
- Kidney-exchange programs. Patient-donor pairs form a general graph; a maximum (weighted) matching maximizes life-saving transplants. Production matching engines run Edmonds-style algorithms, often the weighted variant.
- VLSI and EDA. Chip-layout and via-minimization steps reduce to matching on non-bipartite grids.
- Christofides' TSP approximation. Its 3/2-approximation for metric TSP needs a minimum-weight perfect matching on odd-degree vertices — a weighted blossom computation is the workhorse step.
- Scheduling and sports leagues. Round-robin pairing, task pairing, and roommate-style assignments are general matchings.
- Computational chemistry. Kekulé structures (assigning double bonds) are perfect matchings on the molecular graph.
Libraries expose it directly: NetworkX's max_weight_matching, LEMON, Boost Graph, and Vladimir Kolmogorov's Blossom V for the min-cost perfect-matching variant used across computer vision and OR.
Blossom vs. its cousins: the tradeoff
The natural comparison is against bipartite matching algorithms and the flow-based approach:
- vs. Hopcroft-Karp (O(E·√V)): Hopcroft-Karp is faster and far simpler to implement, but it is only correct on bipartite graphs. On a graph with any odd cycle it silently undercounts. Blossom's entire reason to exist is handling those odd cycles — you pay implementation complexity for correctness on general graphs.
- vs. max-flow reductions: Bipartite matching reduces cleanly to max-flow, but there is no such clean flow reduction for general matching — the odd-set constraints in Edmonds' matching polytope have no unit-capacity flow analog. This is precisely why a bespoke algorithm was needed.
- vs. Micali-Vazirani: MV is asymptotically best at O(E·√V) but notoriously hard to implement correctly; its full proof took Vazirani decades. Most practitioners use the O(V^3) blossom-with-labeling because it is simpler and fast enough.
Rule of thumb: bipartite → Hopcroft-Karp; general and correctness-critical → blossom; huge general graphs where every factor matters → MV.
Pitfalls, failure modes, and significance
Failure modes. The classic bug is running a bipartite augmenting search on a graph you assumed was bipartite but that contains an odd cycle — you get a plausible-looking but non-maximum matching with no error thrown. Implementation pitfalls specific to blossoms: (1) getting the blossom base (lowest common ancestor of the two even vertices) wrong, which corrupts the lift; (2) botching path lifting so the recovered augmenting path re-uses a vertex; (3) forgetting that blossoms can nest, so contraction must be recursive.
- Always confirm whether your graph is bipartite first — if so, use the simpler, faster algorithm.
- For weighted matching, use the primal-dual (Hungarian-style) blossom algorithm; the cardinality version does not respect edge weights.
Significance. Beyond the algorithm, Edmonds' 1965 paper argued that polynomial time is the right definition of "efficient," seeding the theory of P vs. NP and the matching polytope. It remains one of the deepest positive results in algorithm design: a genuinely hard combinatorial obstacle (odd cycles) tamed by a single elegant idea (contract and lift).
| Algorithm | Graph class | Time complexity | Note |
|---|---|---|---|
| Augmenting BFS/DFS | Bipartite | O(V·E) | Fails on odd cycles |
| Hopcroft-Karp | Bipartite | O(E·√V) | Phased augmenting paths |
| Edmonds' Blossom (original) | General | O(V^4) | First polynomial-time result, 1965 |
| Blossom + labeling (Gabow) | General | O(V^3) | No explicit shrink; practical default |
| Micali-Vazirani | General | O(E·√V) | Best known; hard correctness proof |
| Blossom V (Kolmogorov) | General (weighted) | O(V^3) practical | State-of-the-art min-cost implementation |
Frequently asked questions
Why can't I just use a normal augmenting-path search on any graph?
Plain augmenting-path search assumes alternating-path parity is unambiguous, which holds only in bipartite graphs. An odd cycle lets a vertex be reached by both an even- and odd-length alternating path, so the search commits to the wrong parity and misses valid augmentations. It returns a matching that looks fine but is not maximum, with no error raised. The blossom step is exactly what repairs this.
What is a 'blossom,' concretely?
A blossom is an odd-length alternating cycle discovered when an edge connects two 'even' (outer) vertices in the same alternating tree. It has 2k+1 vertices and k matched edges, with one vertex (the base) reachable from the root by an even alternating path. Contracting the whole cycle into a single super-vertex removes the parity conflict so the search can continue correctly.
What is the actual time complexity?
Edmonds' original algorithm was about O(V^4). Using a labeling scheme that avoids physically shrinking the graph (Gabow), a single augmenting-path search costs O(V^2) and the total is O(V^3) — the common library and textbook bound. The asymptotically best is Micali-Vazirani at O(E·√V), though it is much harder to implement correctly.
How is this different from the Hungarian algorithm?
The Hungarian (Kuhn-Munkres) algorithm solves minimum-cost/maximum-weight matching on bipartite graphs. The basic blossom algorithm solves maximum-cardinality matching on general graphs, ignoring weights. There is a weighted, primal-dual blossom algorithm that generalizes the Hungarian approach to non-bipartite graphs — that is what kidney-exchange and Christofides' TSP use.
Can the blossom algorithm handle edge weights?
The cardinality version cannot — it only maximizes the number of edges. For weights you need the primal-dual weighted blossom algorithm, which maintains dual variables on vertices and odd sets and enforces complementary slackness. Vladimir Kolmogorov's Blossom V is the standard high-performance implementation for minimum-cost perfect matching used in vision and operations research.
Why does Edmonds' 1965 paper matter beyond matching?
'Paths, Trees, and Flowers' gave the first polynomial-time algorithm for general matching, but its lasting impact is conceptual: Edmonds explicitly proposed polynomial time as the definition of an 'efficient' algorithm and introduced the matching polytope. This framing directly seeded the theory of P versus NP and modern combinatorial optimization.