The loop
for (int s = mask; s; s = (s - 1) & mask) {
// s runs over all NON-EMPTY submasks of mask, in decreasing order
}
// handle s == 0 separately if the empty submask mattersOr, including zero:
for (int s = mask; ; s = (s - 1) & mask) {
// ...
if (s == 0) break;
}Why it works
s - 1 clears the lowest set bit of s and sets all bits below it. ANDing with mask keeps only bits that belong to the mask. The result is the next smaller submask — and every submask is visited exactly once, in strictly decreasing numeric order.
The bound
Each element is in one of three states: in the submask, in the mask but not the submask, or in neither. So iterating over all masks and all their submasks is , not .
| 15 | |||
| 18 | — | ||
| 20 | — |
So is affordable up to .
What it is for
Set partitioning
// minimum number of valid groups covering `full`
dp[0] = 0;
for (int mask = 1; mask < (1 << n); mask++)
for (int s = mask; s; s = (s - 1) & mask)
if (valid[s]) dp[mask] = min(dp[mask], dp[mask ^ s] + 1);Symmetry breaking: always assign the lowest set bit of mask to the current group. That avoids generating the same partition in orders and typically gives a 10× speedup:
int low = mask & -mask;
for (int s = mask; s; s = (s - 1) & mask)
if (s & low) { /* only submasks containing the lowest element */ }Subset convolution
is directly, or with ranked SOS DP — the difference between and .
Other uses
- Steiner tree — merge two sub-trees at a vertex.
- TSP with grouped cities, set cover, exact cover.
- Counting matchings in a small graph by splitting off one vertex’s partner.
- Any DP whose transition splits a set into two parts.
Supermasks
The dual loop, over all masks containing mask within bits:
for (int s = mask; s < (1 << n); s = (s + 1) | mask) { /* ... */ }Also in total. See Enumerating Supermasks.
Submasks of a fixed size
Use Gosper’s hack to iterate all masks with exactly bits:
for (unsigned v = (1u<<k)-1; v < (1u<<n); ) {
// process v
unsigned c = v & -v, r = v + c;
v = r | (((v ^ r) >> 2) / c);
}per mask, in increasing numeric order.
Avoiding the entirely
When the transition is a subset sum rather than an arbitrary split, SOS DP does the same work in :
Before writing a loop, ask whether the inner sum is really an arbitrary partition or just a subset aggregation — the latter is much cheaper.
See also: SOS DP · Bitmask DP · Enumerating Supermasks