Problem 90 — Cube Digit Pairs

solved Fri, 18 Jul 2025, 22:30 · level 5 · difficulty 15% projecteuler.net github

Each of the six faces on a cube has a different digit ($0$ to $9$) written on it; the same is done to a second cube. By placing the two cubes side-by-side in different positions we can form a variety of $2$-digit numbers.

For example, the square number $64$ could be formed:


In fact, by carefully choosing the digits on both cubes it is possible to display all of the square numbers below one-hundred: $01$, $04$, $09$, $16$, $25$, $36$, $49$, $64$, and $81$.

For example, one way this can be achieved is by placing $\{0, 5, 6, 7, 8, 9\}$ on one cube and $\{1, 2, 3, 4, 8, 9\}$ on the other cube.

However, for this problem we shall allow the $6$ or $9$ to be turned upside-down so that an arrangement like $\{0, 5, 6, 7, 8, 9\}$ and $\{1, 2, 3, 4, 6, 7\}$ allows for all nine square numbers to be displayed; otherwise it would be impossible to obtain $09$.

In determining a distinct arrangement we are interested in the digits on each cube, not the order.

  • $\{1, 2, 3, 4, 5, 6\}$ is equivalent to $\{3, 6, 4, 1, 2, 5\}$
  • $\{1, 2, 3, 4, 5, 6\}$ is distinct from $\{1, 2, 3, 4, 5, 9\}$

But because we are allowing $6$ and $9$ to be reversed, the two distinct sets in the last example both represent the extended set $\{1, 2, 3, 4, 5, 6, 9\}$ for the purpose of forming $2$-digit numbers.

How many distinct arrangements of the two cubes allow for all of the square numbers to be displayed?


Problem Analysis

At its core this is a combinatorics problem about counting subsets. A cube is fully described by the set of six distinct digits printed on its faces - the physical orientation of the faces is irrelevant, because any face can be rotated into view. So a cube is simply a 6-element combination (an unordered selection, with no element repeated) drawn from the ten digits {0, ..., 9}. The number of such combinations is the binomial coefficient C(10, 6) = 210. Recognising this change of representation is the entire trick: a tangible object with rotatable faces becomes a plain set, and the problem dissolves into counting.

An "arrangement" is a pair of cubes, and the problem states the pair is unordered: cube A beside cube B is the same arrangement as cube B beside cube A. Counting unordered pairs with repetition allowed - two identical cubes are a legitimate physical arrangement - gives C(210 + 1, 2) = 22,155 candidate pairs. That is a tiny number, so a brute-force search over every pair is the natural and optimal strategy. For each pair I test the nine two-digit squares below 100 (01, 04, 09, 16, 25, 36, 49, 64, 81). Two observations make that test clean: each square can be formed with either cube supplying the tens digit, so the check considers both orientations; and the 6/9 flip rule means a face showing 6 can also serve as 9 and vice versa, so "can this cube show a 6 or 9?" reduces to "is 6 or 9 present?". The overall complexity is O(C(10,6)^2 * 9) - effectively constant for fixed input, completing in well under a millisecond in C.

Solution Approach

Brute-Force Combination Enumeration (Python and C)

Both files implement the identical algorithm; only the language idioms differ. I chose brute force deliberately because, as the analysis shows, the search space is minuscule. When a problem fits comfortably under roughly 10^7 operations, correctness and clarity matter far more than algorithmic cleverness.

Step 1 - enumerate the cubes. In Python I call itertools.combinations(range(10), 6), which yields all 210 six-element subsets in lexicographic order. In C I reproduce the same enumeration with six nested loops whose index bounds enforce a strictly increasing sequence (a < b < c < d < e < f), storing the digits in a fixed all_cubes[210][6] array. Both produce exactly the same 210 cubes.

Step 2 - encode the square targets. The Python solution computes the nine squares at runtime, formatting each as a two-character string and splitting it into tens and units digits. The C solution hard-codes the nine digit pairs as a static int squares[9][2]. Both are equally correct; the C version trades a little flexibility for directness.

Step 3 - the display predicate. The helper can_display(cube, digit) returns true if the digit is on the cube, or - when the target is 6 or 9 - if either 6 or 9 is present. This single function captures the only subtle rule in the problem, so I isolated it rather than scattering the condition through the pairing loop.

Step 4 - the pair check. can_pair_display_all loops over the nine square pairs (a, b) and requires that for each one, either (cube1 shows a and cube2 shows b) or (cube1 shows b and cube2 shows a). The disjunction covers both physical placements. If any square fails, the pair is rejected immediately - a short-circuit that prunes most pairs after only a few iterations.

Step 5 - count unordered pairs. The outer loops run for i in range(n): for j in range(i, n). Starting j at i (not i + 1) counts each unordered pair once and crucially admits a cube paired with an identical copy of itself.

workbench

Test cases

categoryinputanswer
main 1217

Results

solutioncategoryanswerverdict avg seconds cavg seconds py
p0090_s0 main 1217 correct 0.000673 (63) 0.010537 (63)

Files

Tags & blogs