Purpose: Solve the Travelling Salesman Problem exactly in time and memory — the classic bitmask DP. Also called the Bellman-Held-Karp algorithm.

Algorithm

  1. Fix vertex as the start.
  2. State: dp[mask][i] = cheapest path that starts at , visits exactly the set mask of vertices, and currently sits at .
  3. Base: dp[1][0] = 0 (only vertex 0 visited, standing on it).
  4. Transition: for every mask, every mask with a finite value, and every mask:
  5. Answer: for a tour, or for an open path.

Code

const long long INF = 1e18;
 
long long tsp(int n, vector<vector<long long>>& w) {
    vector<vector<long long>> dp(1 << n, vector<long long>(n, INF));
    dp[1][0] = 0;
 
    for (int mask = 1; mask < (1 << n); mask++) {
        if (!(mask & 1)) continue;                    // must contain vertex 0
        for (int i = 0; i < n; i++) {
            if (!(mask >> i & 1) || dp[mask][i] == INF) continue;
            for (int j = 0; j < n; j++) {
                if (mask >> j & 1) continue;
                int nm = mask | (1 << j);
                dp[nm][j] = min(dp[nm][j], dp[mask][i] + w[i][j]);
            }
        }
    }
 
    long long best = INF;
    int full = (1 << n) - 1;
    for (int i = 1; i < n; i++)
        if (dp[full][i] != INF) best = min(best, dp[full][i] + w[i][0]);
    return best;
}

Reconstruct the tour by storing a par[mask][i] array, or by walking backwards and re-deriving each predecessor.

Paradigm

Dynamic programming over subsets. The insight is that a partial tour’s future cost depends only on which vertices remain and where you are — not on the order you visited them in. That collapses orderings into states.

Complexity

  • Time:
  • Space: — this is usually the binding constraint
states × transitionsmemory (8-byte cells)
154 MB
1838 MB
20168 MB — too much
22738 MB — no

Proof of Correctness

Claim: dp[mask][i] is the minimum cost of a path from through exactly the vertices of mask, ending at .

Induction on popcount(mask). Base: dp[1][0] = 0 is trivially correct. Step: any optimal path realising dp[mask][i] has a well-defined second-to-last vertex . Deleting leaves a path over mask \ {i} ending at , which by the inductive hypothesis costs at least dp[mask ^ (1<<i)][k]. The transition considers exactly all such , so it takes the minimum over all possible optimal decompositions. Conversely every value the transition produces corresponds to a real path, so no under-counting occurs. ∎

Variants / Use Cases

  • Path instead of cycle — drop the closing edge
  • Fixed start and end — force the final vertex
  • Bitmask DP generally — assignment problems, set cover, Hamiltonian counting, matching in small graphs
  • Dreyfus-Wagner — the same subset-DP idea for Steiner trees
  • Held-Karp lower bound — a different Held-Karp result: a 1-tree Lagrangian relaxation used to prune branch-and-bound TSP solvers on large instances
  • Approximation insteadChristofides gives a guarantee in polynomial time for metric TSP
  • Memory relief — iterate masks in increasing popcount and keep only two layers, or use float/int32 costs