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 matters

Or, 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