Teaser 1892: Puzzling present
From The Sunday Times, 20th December 1998 [link]
I have received an astonishing letter from a fellow puzzle-setter. He writes:
“I am sending you a puzzle in the form of a parcel consisting of an opaque box containing some identical marbles, each weighing a whole number of grams, greater than one gram. The box itself is virtually weightless. If I told you the total weight of the marbles, you could work out how many there are.”
He goes on:
“To enable you to work out the total weight of the marbles I am also sending you a balance and a set of equal weights, each weighing a whole number of grams, whose total weight is two kilograms. Bearing in mind what I told you above, these weights will enable you to calculate the total weight of the marbles and hence how many marbles there are.”
I thought that he was sending me these items under seperate cover, but I had forgotten how mean he is. He went on:
“I realise that I can save on the postage. If I told you the weight of each weight you would still be able to work out the number of marbles. Therefore I shall not be sending you anything.”
How many marbles were there?
This puzzle is included in the book Brainteasers (2002). The puzzle text above is taken from the book.
[teaser1892]
Jim Randell 8:55 am on 27 September 2020 Permalink |
(See also: Enigma 1606).
There must be a prime number of balls, each weighing the same prime number of grams.
This Python program uses the same approach I took with Enigma 1606 (indeed if given a command line argument of 4000 (= the 4kg total of the weights) it can be used to solve that puzzle too).
It runs in 48ms.
Run: [ @repl.it ]
from enigma import Primes, isqrt, divisor, group, arg, printf # total weights T = arg(2000, 0, int) # find prime squares up to T squares = list(p * p for p in Primes(isqrt(T))) printf("[T={T}, squares={squares}]") # each weight is a divisor of T for w in divisor(T): # make a "by" function for weight w def by(p): (k, r) = divmod(p, w) return (k if r > 0 else -k) # group the squares into categories by the number of weights required d = group(squares, by=by) # look for categories with only one weight in ss = list(vs[0] for vs in d.values() if len(vs) == 1) # there should be only one if len(ss) != 1: continue # output solution p = ss[0] printf("{n}x {w}g weights", n=T // w) printf("-> {p}g falls into a {w}g category by itself") printf("-> {p}g = {r} balls @ {r}g each", r=isqrt(p)) printf()Solution: There are 37 marbles.
There are 4× 500g weights (2000g in total), and when these are used to weigh the box we must find that it weighs between 1000g (2 weights) and 1500g (3 weights). The only prime square between these weights is 37² = 1369, so there must be 37 balls each weighing 37g.
Telling us that “if I told you the weight of the weights you would be able to work out the number of marbles” is enough for us to work out the number of marbles, without needing to tell us the actual weight. (As there is only one set of weights that gives a category with a single prime square in). And we can also deduce the set of weights.
However, in a variation on the puzzle where the set of weights total 2200g, we find there are two possible sets of weights that give a category with a single square in (8× 275g and 4× 550g), but in both cases it is still 1369 that falls into a category by itself, so we can determine the number (and weight) of the marbles, but not the weight (and number) of the weights. So the answer to the puzzle would still be the same.
Likewise, if the set of weights total 3468g, there are 3 possible sets of weights that give a category with a single square in (6× 578g, 4× 867g and 3× 1156g). However in each of these cases 2809 falls into a category by itself, and so the solution would be 53 marbles each weighing 53g. Which is the answer to Enigma 1606.
LikeLike
Frits 11:36 pm on 27 September 2020 Permalink |
from enigma import SubstitutedExpression from collections import defaultdict # list of prime numbers P = {2, 3, 5, 7} P |= {x for x in range(11, 45, 2) if all(x % p for p in P)} # list of squared prime numbers P2 = [p * p for p in P] # check if only one total lies uniquely between k weights and k+1 weights def uniquerange(weight): group = defaultdict(list) for total in P2: # total lies between k weights and k+1 weights k = total // weight if group[k]: group[k].append(total) else: group[k] = [total] singles = [group[x][0] for x in group if len(group[x]) == 1] if len(singles) == 1: return singles[0] return 0 # the alphametic puzzle p = SubstitutedExpression( [ # ABCD is a weight and a divisor of 2000 "2000 % ABCD == 0", "uniquerange(ABCD) != 0", ], answer="(ABCD, uniquerange(ABCD))", env=dict(uniquerange=uniquerange), # external functions verbose=0, d2i="", # allow number representations to start with 0 distinct="", # allow variables with same values ) # Print answers for (_, ans) in p.solve(): print(f"{int(2000/ans[0])} x {ans[0]}g weigths") print(f"-> {ans[1]}g falls into a {ans[0]}g category by itself") print(f"-> {ans[1]}g = {ans[1] ** 0.5} balls @ {ans[1] ** 0.5}g each")LikeLike