From The Sunday Times, 18th April 1982 [link]
The Manager of a large company greeted his twelve new computer staff. “You have been given consecutive, five-digit, Staff Reference Numbers (SRN). I remember numbers by finding their prime factors, using mental arithmetic — pre-computer vintage. Why not try it? If you would each tell me what factors you have, without specifying them (and ignoring unity), I should be able to work out your SR numbers”.
John said: “My number is prime.”
Ted said ” I have two prime factors. Your number follows mine doesn’t it, Les?”
Ian said: “I also have two, one of which squared. Alan’s just before me on the list.”
Sam said: “One of mine is to the power four. The last two digits of my SRN give me the other prime factor.”
Pete said: “I’ve got one factor to the power four as well. The other one is my year of birth.”
Brian said: “My number has one prime factor cubed and two others, both squared.”
Chris said: “I’m the only one with four factors, one of which is squared. Fred’s number is one less than mine.”
Dave started to say: “Kevin’s SRN is the one after mine, which …” when the Manager interrupted. “I can now list all twelve!”
List the twelve people, by initials, in increasing order of SRNs. What is Sam’s SRN?
This was the final puzzle to go by the title “Brain teaser“. The next puzzle was “Brainteaser 1030“.
This puzzle is included in the book The Sunday Times Book of Brainteasers (1994).
[teaser1029]
Jim Randell 6:18 am on 3 August 2025 Permalink |
If the largest possible total is 69, then there must be 3 dice and the largest number in the set is 23.
The other numbers must be from 1 to 22, from which we can remove any number that is itself a square, or if a double or treble would give a square. Or where that number with 23 or double 23 would give a square.
This Python program runs in 66ms. (Internal runtime is 2.6ms).
from enigma import (irange, sq, subsets, printf) # squares up to 69 sqs = set(sq(i) for i in irange(1, 8)) # there must be 3 dice, with a largest number of 23 # choose the remaining 5 numbers ns = list(x for x in irange(1, 22) if sqs.isdisjoint({x, 2*x, 3*x, x + 23, x + 46, 2*x + 23})) for ds in subsets(ns, size=5, fn=list): ds.append(23) # check possible throws with 2 and 3 dice if any(sum(ss) in sqs for ss in subsets(ds, min_size=2, max_size=3, select='R')): continue # output solution printf("dice = 3x {ds}")Solution: The numbers on each die are: 7, 10, 14, 17, 20, 23.
And so the possible throws are:
Avoiding the square numbers in the range [7 .. 69] = 9, 16, 25, 36, 49, 64 (as well as some non-square numbers in this range).
LikeLike
Jim Randell 11:03 am on 3 August 2025 Permalink |
Or, with more generic code.
This Python program has an internal runtime of 3.4ms.
from enigma import (irange, powers, inf, first, le, subsets, decompose, divisors_pairs, arg, printf) # consider up to k dice combinations of x with m combine = lambda x, m, k: (x + i * x + j * m for (i, j) in decompose(irange(0, k - 1), 2, increasing=0, sep=0, min_v=0)) # solve for k dice, with n faces and a max value of m def solve(k, n, m): # squares up to k.m sqs = set(first(powers(1, inf, 2), count=le(k * m))) if any(i * m in sqs for i in irange(1, k)): return # the candidate numbers (other than m) ns = list(x for x in irange(1, m - 1) if not any(t in sqs for t in combine(x, m, k))) # choose numbers for the remaining faces for ds in subsets(ns, size=n - 1, fn=list): ds.append(m) # check up to k throws if not any(sum(ss) in sqs for ss in subsets(ds, min_size=2, max_size=k, select='R')): yield ds # solve the puzzle for a max throw of 69 M = arg(69, 0, int) for (k, m) in divisors_pairs(M, every=1): if not (k > 1 and m > 8): continue for ds in solve(k, 6, m): printf("dice = {k}x {ds}")This program allows us to explore similar problems with other largest totals.
For a largest total of 87 there are 3 sets of 3 dice. And for a largest total of 99 there are 35 sets of 3 dice.
The first set of 4 dice appears at a largest total of 120:
LikeLike
Frits 11:31 am on 3 August 2025 Permalink |
from itertools import combinations, product # possible square totals sqs = {i * i for i in range(1, 9)} # dice that can cause a square total invalid = {n for n in range(1, 23) for i in range(4) for j in range(4 - i) if i * n + j * 23 in sqs} rng = set(range(1, 23)) - invalid # dice pairs that can cause a square total invalid_pairs = {(x, y) for x, y in combinations(rng, 2) if x + y in sqs or x + y + 23 in sqs} # choose 5 dice (besides 23) for d5 in combinations(rng, 5): # check possible dice pairs from these dice if any(d2 in invalid_pairs for d2 in combinations(d5, 2)): continue # check rolling of 3 dice (we have already checked combinations with 23) if any(sum(d3) in sqs for d3 in product(d5, repeat=3)): continue print("answer:", d5 + (23, ))LikeLike
Frits 12:14 pm on 3 August 2025 Permalink |
A little bit more efficient.
from itertools import combinations # possible square totals sqs = {i * i for i in range(1, 9)} # dice that can cause a square total invalid = {n for n in range(1, 23) for i in range(4) for j in range(4 - i) if i * n + j * 23 in sqs} rng = set(range(1, 23)) - invalid # dice pairs that can cause a square total invalid_pairs = {(x, y) for x, y in combinations(rng, 2) if x + y in sqs or 2 * x + y in sqs or x + 2 * y in sqs or x + y + 23 in sqs} # choose 5 dice (besides 23) for d5 in combinations(rng, 5): # check possible dice pairs from these dice if any(d2 in invalid_pairs for d2 in combinations(d5, 2)): continue # check total of 3 different top faces if any(sum(d3) in sqs for d3 in combinations(d5, 3)): continue print("answer:", d5 + (23, ))LikeLike
Frits 2:02 pm on 3 August 2025 Permalink |
In my first program itertools.combinations_with_replacement() is more suitable than product() (after reviewing Jim’s code).
This version is again a bit more efficient (especially with CPython).
from itertools import combinations # possible square totals sqs = {i * i for i in range(1, 9)} # dice that can cause a square total invalid = {n for n in range(1, 23) for i in range(4) for j in range(4 - i) if i * n + j * 23 in sqs} rng = set(range(1, 23)) - invalid # dice pairs that can cause a square total invalid_pairs = {(x, y) for x, y in combinations(rng, 2) if x + y in sqs or 2 * x + y in sqs or x + 2 * y in sqs or x + y + 23 in sqs} # add <k> top face numbers def solve(k, ns, ss=tuple()): if k == 0: yield ss else: for i, n in enumerate(ns): # check for possible square totals if ss and any((s, n) in invalid_pairs for s in ss): continue yield from solve(k - 1, ns[i + 1:], ss + (n, )) # choose 5 other top face numbers (besides 23) for s in solve(5, sorted(rng)): print("answer:", s + (23, ))LikeLike
Frits 3:44 pm on 4 August 2025 Permalink |
Another.
from itertools import combinations # possible square totals sqs = {i * i for i in range(1, 9)} # all combinations with x and y c2 = lambda x, y: [2*x, 3*x, x + y, x + 2*y, 2*x + y] c3 = lambda x, y, z: [x + y, x + 2*y, 2*x + y, x + y + z] rng = [x for x in range(1, 23) if x not in sqs and sqs.isdisjoint(c2(x, 23))] # dictionary of numbers that may be paired with a number (including itself) d = {x: {y for y in rng if sqs.isdisjoint(c3(x, y, 23))} for x in rng} # choose 5 other top face numbers (besides 23) for d5 in combinations(d.keys(), 5): # each number must pair with other selected numbers if any(not d[n].issuperset(d5) for n in d5): continue print("answer:", d5 + (23, ))LikeLike