Home
DSA Visualizer
Advanced Topics
Bitmask DP
Bitmask DP
Bitmask DP is dynamic programming that encodes subsets or assignments as bitmasks, which makes problems solvable when N is small (up to 20).
BASE
Row 0011 is the set {0, 1} — bits read right to left, so city 0 is the last digit.
Filled
1/13
Checks
0/15
Best
—
Every route starts the same way, so the table starts with one cell: dp[{0}][0] = 0 — city 0 visited, standing on it, nothing spent. A cell here reads "these cities have been visited and I am at this one", which is why only 13 of the 64 cells can ever hold anything: the city stood at has to be one of the visited ones, the set has to include the start, and the city stood at can never BE the start — a route leaves city 0 once and does not stand on it again until the tour closes. The rest of the table is not empty, it is impossible.
Next
{0} covered, standing at 0, for 0. Take the road to 1 — it costs 10 — and that is 0 + 10 = 10 to cover {0, 1} ending at 1. That cell was ∞ — nothing had reached it yet — so it becomes 10. One number now stands for every route that covers {0, 1} and ends at 1, whatever order it took to get there.
13 of the 64 cells can ever hold a value. 15 transitions against 6 brute-force tours.
Road costs
Order: 0-1, 0-2, 0-3, 1-2, 1-3, 2-3 — 3 costs make 3 cities, 6 make 4, 10 make 5.
Intuition
The Restriction: Standard DP arrays work well when states are indices (e.g., dp[i]). But what if the state is a set of visited cities or available jobs?
The Solution: Use an integer as a bitmask to represent a set. If the j-th bit is set (1), element j is present/visited.
Since an integer can store up to 30-60 bits, we can represent any subset of size N efficiently if N <= 20.
Concept
Bit Operations Recap:
- Set bit i:
mask | (1 << i) - Check bit i:
(mask >> i) & 1 - Toggle bit i:
mask ^ (1 << i) - All bits set:
(1 << N) - 1
State Definition: Usually dp[mask][current_element], where mask represents the set of visited elements and current_element is the last added item.
How it Works
- Definite State: Identify what needs to be tracked. Usually "what elements are used" (mask) and "where are we now" (index).
- Transitions: Iterate through all subsets (masks) and try adding an available element (unvisited bit).
- Base Cases:
dp[0][...]ordp[1 << start_node][start_node]usually initialized to 0 or cost.
Step-by-Step Breakdown
1. Initialize: Create a DP table of size 2^N * N. Fill with infinity or appropriate default.
2. Base Case: Set starting masks (e.g., visiting the first city).
3. Iterate: Loop through mask from 1 to 2^N - 1.
4. Inner Loop: Loop through u (current node) and v (next node).
5. Update: If u is in mask and v not in mask, update dp[mask | (1<<v)][v].
When to Use
- Problems involving permutations or subsets where N is small (N <= 20).
- Traveling Salesman Problem (TSP).
- Assignment Problems (Assign N jobs to N people).
- Hamiltonian Path/Cycle problems.
When NOT to Use
- When N > 20 (Space/Time 2^N becomes too large).
- When the problem can be solved greedily or using standard flow algorithms.
How to Identify
"Find shortest path visiting all nodes", "Assign N tasks to N workers with min cost", Constraints: N <= 20.
Applying for software engineering roles? Free, no sign-up:
