Purpose: Build a single weighted tree on V vertices that encodes the minimum s-t cut value between every pair of vertices in a graph, using only V - 1 max-flow computations instead of O(V²).
Algorithm
- Start with a tree containing all vertices, initially all connected to some arbitrary root (structure will be rebuilt as edges are found).
- For each vertex
ifrom 1 toV - 1(skipping the root), letp(i)bei’s current parent in the tree. - Compute the minimum
s-tcut betweeniandp(i)in the original graph, and letfbe this cut’s value andSbe the set of vertices oni’s side of this cut. - Set the tree edge weight between
iandp(i)tof. - For every other vertex
jwhose current parent isp(i)and which lies inS, redirectj’s parent toiinstead (since the cut separates them together withi). - If
p(i)itself has a parent outsideS… continue: ifp(p(i))is inS, adjust connections accordingly to maintain tree correctness. - After processing all vertices, the resulting tree is the Gomory-Hu tree: the minimum cut between any two vertices
u, vequals the minimum edge weight along the tree path between them.
Code
// Requires a maxFlowMinCut(n, graph, s, t) function returning {flowValue, sourceSideSet}
vector<int> gomoryHuTree(int n, vector<vector<int>>& capacity) {
vector<int> parent(n, 0);
vector<int> treeWeight(n, 0);
for (int i = 1; i < n; i++) {
auto graphCopy = capacity; // fresh capacities each time
auto [flow, sourceSide] = maxFlowMinCut(n, graphCopy, i, parent[i]);
treeWeight[i] = flow;
for (int j = i + 1; j < n; j++) {
if (parent[j] == parent[i] && sourceSide[j]) {
parent[j] = i;
}
}
// if parent[i]'s own parent ends up on i's side, swap them
if (sourceSide[parent[parent[i]]] && parent[i] != 0) {
parent[i] = parent[parent[i]];
// (full implementations also swap treeWeight bookkeeping here)
}
}
return parent; // combined with treeWeight, defines the Gomory-Hu tree
}Paradigm
Transform and Conquer combined with Greedy. The algorithm transforms the O(V²)-pairwise-cuts problem into V−1 carefully chosen max-flow computations by exploiting cut structure, greedily fixing each vertex’s tree edge using only one min-cut computation against its current parent.
Complexity
- Time: O(V) max-flow computations, so O(V) × (max-flow cost) — typically O(V⁴) to O(V · E · maxflow) depending on the flow algorithm used
- Space: O(V²) for the capacity matrix
Proof of Correctness
Core cut-equivalence property: The Gomory-Hu tree has the property that for any two vertices u, v, the minimum edge weight on the tree path between them equals the true minimum u-v cut value in the original graph — and the two sides of the minimum tree-path edge, when removed, correspond to (a valid) actual minimum cut separating u and v in the original graph.
Why processing against the current parent suffices (sketch): The proof relies on the uncrossing property of minimum cuts: given minimum cuts for two different pairs that “cross” (partially overlap), one can always construct two new minimum cuts that don’t cross and have the same total weight, by taking unions/intersections of the crossing sets. This lets the algorithm always resolve each vertex’s relationship to the tree being built so far using a cut against its current representative parent, without needing to separately verify consistency against every other vertex — the uncrossing property guarantees the partial tree remains consistent as more vertices are processed.
Correctness of pairwise cut recovery: Once the full tree is built, for any pair (u, v), consider the unique path between them in the tree. Removing the minimum-weight edge on this path splits the tree (and correspondingly the vertex set) into two parts; this split corresponds to an actual cut in the original graph with weight equal to that minimum tree edge. By construction (via the uncrossing argument applied inductively), no cheaper u-v cut can exist, so this is exactly the minimum u-v cut. ∎ (Full rigorous proof is intricate — see Gomory & Hu’s original 1961 paper or Gusfield’s simplified construction.)
Variants / Use Cases
- Gusfield’s simplification → avoids graph contraction between steps, computing all cuts against the original graph directly, easier to implement
- All-pairs minimum cut queries → the primary use case, answering any pair’s min-cut in O(1) via a tree-path minimum after O(V) preprocessing
- Network reliability analysis → identifying the weakest link between any two nodes in a network
- Clustering via tree cuts → repeatedly cutting the Gomory-Hu tree’s minimum edges partitions the graph into well-separated clusters
- VLSI and circuit partitioning → minimizing cross connections between arbitrary component pairs