TAOCP 7.2.2.1 Exercise 84

We restart the argument in a way that separates _finding the optimal bound_ from _enumerating all optimal solutions_, because mixing both in a single changing-bound traversal is what caused the failur...

Section 7.2.2.1: Dancing Links

Exercise 84. ▶ [25] [25] Number the options of an XCC problem from 1 to $M$. A minimax solution is one whose maximum option number is as small as possible. Explain how to modify Algorithm C so that it determines all of the minimax solutions (omitting any that are known to be worse than a solution already found).

Verified: yes
Solve time: 2m21s


We restart the argument in a way that separates finding the optimal bound from enumerating all optimal solutions, because mixing both in a single changing-bound traversal is what caused the failure.

Correct modification of Algorithm C

Let each option $O_j$ have index $j \in {1,\dots,M}$. For a partial solution $S$, define

$$ m(S) = \max{ j : O_j \in S }, $$

with $m(\varnothing)=0$.

A minimax solution is an exact cover $S$ minimizing $m(S)$ over all exact covers.

Phase 1: compute the optimal bound $B^*$

We first modify Algorithm C only to search for exact covers while maintaining the best maximum index found, but without any attempt to enumerate solutions.

Maintain a global variable

$$ B \leftarrow M+1. $$

During the search, whenever a solution $S$ is found, update

$$ B \leftarrow \min(B, m(S)). $$

During branching, when trying option $O_j$, prune only if

$$ \max(m(S), j) > B. $$

Crucially, equality is allowed. This ensures that solutions achieving the current best bound are not excluded from consideration, so the final value of $B$ upon termination is indeed

$$ B = B^*. $$

No solutions are output in this phase. Its sole purpose is to compute the optimal value $B^*$.

Phase 2: enumerate all minimax solutions

We rerun Algorithm C with $B$ now fixed to the optimal value $B^*$.

The state variable $m(S)$ is again maintained as before.

Pruning rule

When considering an option $O_j$, prune a branch if

$$ \max(m(S), j) > B^*. $$

This is the correct branch-and-bound condition: any partial solution whose maximum already exceeds the proven optimum cannot lead to a minimax solution.

Output rule

When a complete exact cover $S$ is found, output it iff

$$ m(S) = B^*. $$

No solution is ever output before the bound is fixed, so there is no risk of later invalidation.

Why this is correct

1. Phase 1 computes $B^*$ correctly

The search explores all exact covers that are not already impossible under the current best bound. Because pruning only occurs when $\max(m(S),j) > B$, any solution with maximum exactly equal to the eventual optimum is never excluded during the phase in which it is discovered. Therefore the minimum achievable maximum is eventually recorded in $B$, so at termination

$$ B = B^*. $$

2. Phase 2 enumerates exactly the minimax solutions

Fix $B^*$. Any solution $S$ with $m(S) > B^*$ is pruned as soon as it becomes impossible to stay within the bound, so it is never generated.

Any solution with $m(S) = B^*$ is never pruned and is output at completion.

Any solution with $m(S) < B^*$ cannot exist by definition of $B^*$.

Hence the algorithm outputs exactly all minimax solutions.

3. No dependence on a changing bound during output

The key defect in the original solution was coupling output to a mutable $B$. Here, output occurs only after $B^*$ is fixed, so there is no inconsistency or need for retraction.

Relation to Algorithm C

The modification is minimal in structure:

  • Add variable $m(S)$ propagated along recursion.

  • Add a branch-and-bound test using a global bound $B$.

  • Run Algorithm C twice:

  • once to compute $B^*$,

  • once to enumerate all solutions satisfying the optimal bound.

Cover and uncover operations of Algorithm C remain unchanged.

This yields a correct minimax version of Algorithm C that enumerates all and only solutions with minimal possible maximum option index.