Purpose: Enumerate all maximal cliques of an undirected graph. With pivoting, it runs in β which is optimal, because a graph can have that many maximal cliques (Moon-Moser).
Algorithm
Recursive backtracking on three sets:
- β the clique built so far,
- β candidates that can still extend ,
- β vertices already processed (used to avoid reporting the same clique twice).
BronKerbosch(R, P, X):
if P and X are both empty:
report R as a maximal clique
choose a pivot u from P βͺ X maximising |P β© N(u)|
for each v in P \ N(u):
BronKerbosch(R βͺ {v}, P β© N(v), X β© N(v))
P β P \ {v}
X β X βͺ {v}
Why the pivot. Any maximal clique must contain either or a vertex not adjacent to . So it suffices to branch on , and choosing to maximise makes that set as small as possible. Without pivoting the algorithm still works but is dramatically slower.
Code
Bitset version β the one to use, since all set operations become single machine words:
int n;
vector<unsigned long long> adj; // adj[v] = bitmask of neighbours (n <= 64)
vector<unsigned long long> cliques;
void bk(unsigned long long R, unsigned long long P, unsigned long long X) {
if (!P && !X) { cliques.push_back(R); return; }
// pivot: vertex of P|X with the most neighbours inside P
int pivot = -1, best = -1;
unsigned long long PX = P | X;
for (unsigned long long t = PX; t; t &= t - 1) {
int u = __builtin_ctzll(t);
int c = __builtin_popcountll(P & adj[u]);
if (c > best) { best = c; pivot = u; }
}
unsigned long long cand = P & ~adj[pivot];
for (unsigned long long t = cand; t; t &= t - 1) {
int v = __builtin_ctzll(t);
bk(R | (1ULL << v), P & adj[v], X & adj[v]);
P &= ~(1ULL << v);
X |= (1ULL << v);
}
}Paradigm
Backtracking with pruning. prunes duplicates; the pivot prunes branches.
Complexity
- Time: worst case with pivoting β matching the maximum possible number of maximal cliques
- With a degeneracy ordering at the top level: where is the graph degeneracy β near-linear on sparse real-world graphs
- Space: for the adjacency bitsets, recursion depth
Correctness
Every reported is a clique by construction (each added is adjacent to all of ). It is maximal because means no vertex is adjacent to all of . No clique is reported twice: once moves from to , any later branch containing hits a non-empty at its would-be reporting point and is suppressed. Completeness follows from the pivot argument above. β
Variants / Use Cases
- Maximum clique β take the largest reported clique, or use a dedicated branch-and-bound solver with a colouring bound (much faster when you only need the maximum)
- Maximum independent set β run on the complement graph
- Minimum vertex cover β minus the maximum independent set (KΓΆnigβs theorem gives a flow solution in bipartite graphs)
- Graph colouring lower bounds β the clique number bounds the chromatic number from below
- Community detection / social network analysis β the original motivation for degeneracy-ordered Bron-Kerbosch
- Maximum Clique and Independent Set β the topic page