Design a site like this with WordPress.com

## Tagged: by: Peter Good Toggle Comment Threads | Keyboard Shortcuts

• ## Teaser 3143: Pipe fittings A plumber had three thin metal pipes with square, rectangular and elliptical cross-sections. In order to fit them into his van, he slid the rectangular pipe inside the elliptical pipe and the elliptical pipe inside the square pipe, before placing the pipe assembly in the van. There are four points where the pipes all touch, as shown in the diagram. The maximum and minimum widths of the elliptical and rectangular pipes and the diagonal width of the square pipe were all even numbers of mm less than 1000, of which one was a perfect square.

What were the five widths (in increasing order)?

[teaser3143]

• #### Jim Randell 5:20 pm on 16 December 2022 Permalink | Reply

If we consider the diagram to be centred on the origin (0, 0), and the point where all four figures meet in the (+, +) quadrant is (x, y), then the rectangle has dimensions (2x, 2y) and the diagonal of the square is 2z where z = x + y.

And if the ellipse has semi-major axis a and semi-minor axis b, then the equation of the tangent at the point (p, q) is:

x(p/a²) + y(q/b²) = 1

and this is the same as the line that defines the side of the square tube:

x + y = z

Hence:

a² = x.z
b² = y.z

Assuming exactly one of the required widths is a perfect square gives a unique answer to the puzzle.

This Python program runs in 134ms. (Internal runtime is 76ms).

Run: [ @replit ]

```from enigma import (irange, decompose, is_square, icount_exactly as icount, printf)

# choose a value for z
for z in irange(5, 499):
# consider values for x and y
for (y, x) in decompose(z, 2, increasing=1, sep=1, min_v=1):
# calculate values for a and b
a = is_square(x * z)
b = is_square(y * z)
if a and b:
# calculate the widths (in increasing order)
ws = sorted(2 * n for n in (a, b, x, y, z))
# check exactly one of the widths is a perfect square
if icount(ws, is_square, 1):
# output solution
printf("ws={ws} [z={z} x={x} y={y} a={a} b={b}]")
```

Solution: The widths are (in mm): 180, 300, 320, 400, 500.

Swapping [[ `icount_exactly()` ]] for [[ `icount_at_least()` ]] reveals 4 further solutions, so it is necessary to assume exactly one of the widths is a perfect square.

Like

• #### Jim Randell 6:09 pm on 16 December 2022 Permalink | Reply

Or we can use the [[ `pythagorean_triples()` ]] function from the enigma.py library to get a more efficient program.

This Python program runs in 58ms. (Internal runtime is 777µs).

Run: [ @replit ]

```from enigma import (pythagorean_triples, div, sq, is_square, icount_exactly as icount, printf)

# generate values for a, b, z, st: a^2 + b^2 = z^2
for (b, a, z) in pythagorean_triples(499):
# calculate x and y
(x, y) = (div(sq(n), z) for n in (a, b))
if x is None or y is None: continue
# calculate the widths (in increasing order)
ws = sorted(2 * n for n in (a, b, x, y, z))
# check exactly one of the widths is a perfect square
if icount(ws, is_square, 1):
# output solution
printf("ws={ws} [z={z} a={a} b={b} x={x} y={y}]")
```

Like

• ```% A Solution in MiniZinc
include "globals.mzn";

% x, y = rectangle dimensions and a,b ellipse semi major/minor axes
var 4..498:x; var 4..498:y;
var 4..498:a; var 4..498:b;
var 4..498:z;

constraint a > b /\ z = x + y;

% Using Jim's derivation and named variables
constraint a * a == x * z /\ b * b == y * z;

predicate is_sq(var int: m) =
exists(n in 1..ceil(sqrt(int2float(ub(m))))) (n*n = m );

constraint sum([is_sq(2*a), is_sq(2*b), is_sq(2*x),
is_sq(2*y), is_sq(2*z)]) == 1;

solve satisfy;

output ["Five widths [2a, 2b, 2x, 2y, 2z ] = " ++
show([2*a, 2*b, 2*x, 2*y, 2*z])];

```

Like

• ## Teaser 3134: Stringing along [revised]

An artist hammered thin nails from a pack of 40 into a board to form the perimeter of a rectangle with a 1 cm gap between adjacent nails. He created a work of art by stringing a long piece of wire from one nail to another, such that no section of wire was parallel to an edge of the rectangle. The wire started and ended at two different nails, no nail was used more than once and the length of the wire was a whole number of cm. No longer wire was possible that satisfied the above conditions.

What were the dimensions of the rectangle and the length of the wire chain (in cm)?

This is a revised version of the puzzle posted as Teaser 3134. The underlined text has been changed from the previously published version on The Sunday Times website.

This is the version of the puzzle that appeared in the printed newspaper.

[teaser3134]

• #### Jim Randell 4:01 pm on 15 October 2022 Permalink | Reply

Having solved the (more general) previously published version of this puzzle [link], it is a simple case of adapting my program to account for the additional condition.

For this version I am assuming we want to find the maximum achievable total length of wire between the nails that can be made using a rectangle constructed from up to 40 nails, with the wire strung between nails where no nail is used more than once and consecutive nails are on different edges of the rectangle (i.e. each linear section of wire must cross part of the interior of the rectangle, and be a whole number of centimetres long), and no linear section of wire is parallel to the edges of the rectangle.

You can think of the wire being available in various stiff lengths with looped ends, but these individual links can only ever fit between nails that are a whole number of centimetres apart. We wish to make a chain of these wire links, where each link goes from the end of the previous link to a currently unoccupied nail. What is the longest possible chain that can be made, on a rectangle whose perimeter is constructed from no more than 40 nails spaced 1 cm apart, where each link must cross the interior of the rectangle not parallel to the edges of the rectangle, and the start and end of the complete chain are on different nails.

This Python program runs in 104ms.

Run: [ @replit ]

```from enigma import (irange, ihypot, chain, Accumulator, printf)

# generate possible <x> by <y> rectangles, using (up to) <n> nails
def generate(n):
for y in irange(2, n // 4):
for x in irange(2, (n - 2 * y) // 2):
yield (x, y)

# find paths by adding nails to <vs>
def solve(x, y, nails, vs, d=0):
# return the current path
yield (d, vs)
# choose the next nail
(x1, y1) = vs[-1]
for v in nails:
(x2, y2) = v
(dx, dy) = (x2 - x1, y2 - y1)
if dx == 0 or dy == 0: continue
dd = ihypot(dx, dy)
if dd is not None:
yield from solve(x, y, nails.difference([v]), vs + [v], d + dd)

# collect maximal distance paths
r = Accumulator(fn=max, collect=1)

# consider possible rectangles
for (x, y) in generate(40):
# collect possible edge nails
nails = set()
for i in irange(0, x - 1):
nails.update([(i, 0), (x - i, y)])
for i in irange(0, y - 1):
nails.update([(0, y - i), (x, i)])
# start in the bottom/left quadrant
botm = ((i, 0) for i in irange(0, x // 2))
left = ((0, i) for i in irange(1, y // 2))
for v in chain(botm, left):
for (d, vs) in solve(x, y, nails.difference([v]), [v]):
r.accumulate_data(d, (x, y, vs))

# output solution(s)
printf("max wire length = {r.value} cm")
for (x, y, vs) in r.data:
printf("-> {x} cm by {y} cm grid {vs}")
```

Solution: The rectangle was 12 cm × 8 cm. The total length of wire used was 102 cm.

Here is a diagram of the maximal length layout: Like

• #### Jim Randell 11:28 am on 28 October 2022 Permalink | Reply

In my program above, in order to get a total distance that is a whole number we require the individual segments between consecutive pins in the stringing to be a whole number.

This is a reasonable assumption. As we can show that if we have a collection of positive integers, and at least one of them has a square root that is irrational, then the sum of the square roots of the entire collection is irrational. (See below [*]).

However, this does not mean we cannot construct stringings that are very close to an integer value using segments that are not themselves integers. And this lets us find solutions that are much longer than the published solution.

For example here is a stringing on the 12cm × 8 cm grid that has a total length of 440.999925 cm (i.e. 750 nanometres short of 441 cm). It would be practically impossible to tell this apart from a 441 cm length of wire. Note that in this construction every pin is visited.

If we want more accuracy we can get within 6nm of 438 cm.

[*] The core of the proof is:

Suppose x, y are integers, such that at least one of √x and √y are irrational.

Then (x − y) is also an integer, and:

(x − y) = (√x + √y)(√x − √y)

If (√x + √y) is rational (= p), then:

(√x − √y) = (x − y)/(√x + √y) is also rational (= q)

But then:

√x = (p + q)/2 is rational; and
√y = (p − q)/2 is rational

Which is a contradiction, hence the sum (√x + √y) is irrational.

Like

• #### Hugh Casement 10:16 am on 16 October 2022 Permalink | Reply

The change in wording makes quite a difference to the total length, at least with the solution I worked out.

The puzzle does not seem to be well thought out. That the nails are thin clearly means that we are to ignore their diameter (and the thickness of the wire). But with centimetres as the unit they are not nails at all but pins, and it’s fine fuse wire. Inches would have been somewhat less unrealistic.

I also feel that if the “artist” had allowed himself more nails, the resulting pattern could have been more interesting. For example, 12 occurs in the Pythagorean triangles (9, 12, 15) and (12, 16, 20) as well as (5, 12, 13), which would presumably give more scope. But the length + width of the rectangle must not exceed 20, so we are much restricted.

Like

• #### Jim Randell 12:03 pm on 17 October 2022 Permalink | Reply

@Hugh: Yes for the original wording I found a maximal solution with 24 links. For this revised version there are only 10 links. The rectangle was the same in both cases.

Like

• ## Teaser 3134: Stringing along

From The Sunday Times, 16th October 2022 [link]

An artist hammered thin nails from a pack of 40 into a board to form the perimeter of a rectangle with a 1 cm gap between adjacent nails. He created a work of art by stringing a long piece of wire from one nail to another, such that consecutive nails were on different edges of the rectangle. The wire started and ended at two different nails, no nail was used more than once and the length of the wire was a whole number of cm. No longer wire was possible that satisfied the above conditions.

What were the dimensions of the rectangle and the length of the wire chain (in cm)?

The wording of this puzzle was later revised. The underlined section was changed to a more restrictive condition.

See: Teaser 3134: Stringing along [revised] for the revised puzzle.

[teaser3134]

• #### Jim Randell 5:07 pm on 14 October 2022 Permalink | Reply

(Note: It seems that my initial interpretation of the puzzle may not be the intended one. See below for a more likely interpretation).

It seems we would need to know the dimensions of the rectangle before we determined the maximum length of wire. I considered all rectangles that can be constructed using 40 nails, and found the maximum possible length of wire that touches each edge of the rectangle no more than once.

This Python program tries all possible rectangles, and all possible stringings.

It runs in 275ms.

Run: [ @replit ]

```from enigma import (irange, inf, subsets, tuples, hypot, intr, Accumulator, printf)

# generate possible <x> by <y> rectangles, using <n> nails
def generate(n):
for y in irange(3, inf):
x = (n - 2 * y) // 2
if x < 3: break
yield (x, y)

# calculate length of wire required between points <vs>
def dist(vs):
d = 0
for ((x1, y1), (x2, y2)) in tuples(vs, 2):
d += hypot(x2 - x1, y2 - y1)
if abs(d - intr(d)) < 1e-6:
return d

# collect maximal stringings
r = Accumulator(fn=max, collect=1)

# consider possible rectangles
for (x, y) in generate(40):
# choose top, bottom nails
for (x1, x2) in subsets(irange(1, x - 1), size=2, select="R"):
(T, B) = ((x1, y), (x2, 0))
# choose left, right nails
for (y1, y2) in subsets(irange(1, y - 1), size=2, select="P"):
(L, R) = ((0, y1), (x, y2))
# calculate possible lengths
for vs in [(T, R, B, L), (T, R, L, B), (T, B, R, L)]:
d = dist(vs)
if d is None: continue
printf("[({x}, {y}) {d:g} = {vs}]")
r.accumulate_data(d, (x, y, vs))

printf("max wire length = {r.value:g} cm")
for (x, y, vs) in r.data:
printf("-> {x} cm by {y} cm grid {vs}")
```

Solution: The rectangle was 6 cm × 14 cm, and the wire was 37 cm long.

This program finds what I assume is the required answer (where each section of the wire is an integer length). But by changing the tolerance at line 15 we can find a longer wire that is sufficiently close to an exact whole number of centimetres that it would be physically impossible to determine that it wasn’t.

So we can create a stringing on a 6 cm × 14 cm rectangle that uses 40.0007 cm of wire.

And also a stringing on a 4 cm × 16 cm rectangle that uses 44.99 cm of wire.

Like

• #### Jim Randell 11:19 pm on 14 October 2022 Permalink | Reply

Using a different (and more likely) interpretation of the problem (see below), where each edge of the rectangle may be visited many times (and allowing the corner nails to be used), but each linear section of wire is a whole number of centimetres, we can get a much longer wire.

To be clear: I am assuming we want to find the maximum achievable total length of wire between the nails that can be made using a rectangle constructed from up to 40 nails, with the wire strung between nails where no nail is used more than once and consecutive nails are on different edges of the rectangle (i.e. each linear section of wire must cross part of the interior of the rectangle, and be a whole number of centimetres long).

Here is a quick program to explore that (although there may be some duplication in the patterns found).

It runs in 942ms.

Run: [ @replit ]

```from enigma import (irange, ihypot, chain, Accumulator, printf)

# generate possible <x> by <y> rectangles, using (up to) <n> nails
def generate(n):
for y in irange(2, n // 4):
for x in irange(2, (n - 2 * y) // 2):
yield (x, y)

# find paths by adding nails to <vs>
def solve(x, y, nails, vs, d=0):
# return the current path
yield (d, vs)
# choose the next nail
(x1, y1) = vs[-1]
for v in nails:
(x2, y2) = v
(dx, dy) = (x2 - x1, y2 - y1)
if dx == 0 and (x1 == 0 or x1 == x): continue
if dy == 0 and (y1 == 0 or y1 == y): continue
dd = ihypot(dx, dy)
if dd is not None:
yield from solve(x, y, nails.difference([v]), vs + [v], d + dd)

# collect maximal distance paths
r = Accumulator(fn=max, collect=1)

# consider possible rectangles
for (x, y) in generate(40):
# collect possible edge nails
nails = set()
for i in irange(0, x - 1):
nails.update([(i, 0), (x - i, y)])
for i in irange(0, y - 1):
nails.update([(0, y - i), (x, i)])
# start in the bottom/left quadrant
botm = ((i, 0) for i in irange(0, x // 2))
left = ((0, i) for i in irange(1, y // 2))
for v in chain(botm, left):
for (d, vs) in solve(x, y, nails.difference([v]), [v]):
r.accumulate_data(d, (x, y, vs))

# output solution(s)
printf("max wire length = {r.value} cm")
for (x, y, vs) in r.data:
printf("-> {x} cm by {y} cm grid {vs}")
```

Solution: The rectangle was 12 cm × 8 cm. The total length of wire used was 258 cm.

Here is a diagram of one maximal length arrangement (there are several): Like

• The answer for this one depends on the assumptions being made. I found a different answer by assuming that the wire length was exact and that not all nails are used. I then looked for a number of Pythagorean triangle hypotenuses with a maximum sum (not necessarily alternating x, y edges).

Like

• #### Jim Randell 10:51 pm on 14 October 2022 Permalink | Reply

@Brian: I was assuming that each edge of the rectangle was only used once (and the corners not at all). But the puzzle text only says consecutive nails are on different edges, so if we can visit edges more than once then we can use much more wire. (And get a more artful display into the bargain).

In this case I assumed distance between each consecutive pair of nails was an exact whole number of cm, so that the total length of the wire is as well.

(Although it still seems like we would need to know the size of the rectangle the artist had constructed before we could find the maximum length of wire he could use).

Like

• ## Teaser 3113: The plumber’s buckets

A plumber was trying to empty a tank containing 100 litres of water using three buckets, each marked with a different whole number of litres capacity between 10 and 20 litres. He calculated that he could exactly empty the tank, but only by using all three buckets and completely filling each bucket a different number of times.

He filled and emptied each bucket the calculated number of times but the tank still contained 6 litres of water, because the smallest bucket had a dent that reduced its capacity by 3 litres.

What were the marked capacities of the three buckets?

[teaser3113]

• #### Jim Randell 4:51 pm on 20 May 2022 Permalink | Reply

Perhaps I misread this puzzle, but I couldn’t find a solution that fits the text.

However, I did find a solution where the dent reduces the capacity of the largest bucket (not the smallest) by 3 litres. This is my preferred way to “rescue” the puzzle, as it is a minimal change to the text, and the dent would be less noticeable in the largest bucket. However, another way to rescue the puzzle (but with a different solution) is if the capacity of the smallest bucket is reduced by 2 litres (not 3 litres).

This Python program runs in 58ms.

```from enigma import (
irange, subsets, express, seq_all_different as all_different,
singleton, printf
)

# choose the labelled capacities of the buckets
for bs in subsets(irange(10, 20), size=3):
# there is only one way to use the buckets
qs = singleton(express(100, bs))
if qs is None: continue
# each bucket is used
if 0 in qs: continue
# the number of uses are all different
if not all_different(qs): continue
# largest [was: smallest] bucket must be used twice
if qs[-1] != 2: continue
printf("bs={bs} qs={qs}")
```

Solution: The puzzle, as originally worded, has no solution.

If we look for combinations of (correctly labelled) buckets that can be used (completely filling each bucket a number of times) to empty a 100 litre tank, such that all three buckets must be used, each of them a different number of times, we find there are 5 viable combinations (buckets × uses):

(11, 18, 19) × (4, 1, 2)
(12, 17, 18) × (1, 2, 3)
(12, 17, 18) × (4, 2, 1)
(13, 15, 19) × (1, 2, 3)
(15, 18, 19) × (3, 2, 1)

(And if we require there to be only a single way to use the buckets we can discard the (12, 17, 18) combination, leaving only 3 viable combinations).

The original text asked for a combination where the smallest bucket was used twice, but as we see there are no such combinations.

In my rescued version, where the largest bucket (not the smallest) has the dent, the solution is that the buckets are labelled (11, 18, 19) litres (although they are actually (11, 18, 16) litres).

The published solution was that the buckets are labelled (13, 17, 19) litres (although they are actually (10, 17, 19) litres). Which corresponds to my re-wording of the puzzle given below.

However we can use (correctly labelled) buckets (13, 17, 19) to empty the tank in the following ways:

1× 13 + 4× 17 + 1× 19 = 100
2× 13 + 1× 17 + 3× 19 = 100

So it is not true to say that it can “only [be done] by using all three buckets and completely filling each bucket a different number of times”. (The first line achieves the required result using two of the buckets the same number of times). Hence the requirement for rewording of the puzzle.

But if we suppose “the calculated number of times” requires that there is only one possible way to fill the buckets, then the reworded puzzle also has no solutions. (As there are 2 ways to use these (correctly labelled) buckets to empty the tank).

It is possible that the setter intended that when the plumber sat down to work out how many times to use the buckets, he only considers using each bucket a different number of times. He tried using just one bucket and found it was not possible, then he tried using combinations of two buckets and found none of those were possible, and finally he tried using all three buckets and found that there was a single way they could be used. And he then proceeded to use this calculated number of ways, but when he finished there was 6 litres remaining in the tank, because the smallest bucket’s capacity was reduced by 3 litres from the labelled capacity.

In this scenario, there are 9 candidate bucket combinations, and only one of them has the smallest bucket having 2 uses, so this gives a unique solution, and it is the published solution.

Like

• #### Jim Randell 5:58 pm on 20 May 2022 Permalink | Reply

This might be a stricter interpretation of the puzzle text, which finds a couple more candidate solutions. But still doesn’t find a solution that fits the text.

Instead I have coded it to find the same solution I found above.

There remains an issue as to whether “he filled and emptied each bucket the calculated number of times” is intended to imply that there is only a single way of filling the buckets (each a different non-zero number of times), or he chose one from multiple viable ways. Fortunately this does not change the answer to my “rescued” version of the puzzle.

This Python program runs in 56ms. (Internal run time is 1.58ms).

Run: [ @replit ]

```from enigma import (irange, subsets, express, seq_all_different as all_different, printf)

# find viable ways to use the buckets
def buckets(t, bs):
rs = list()
for qs in express(t, bs):
# each bucket is used
if 0 in qs: return []
# the numbers of uses are all different
if not all_different(qs): return []
# is viable
rs.append(qs)
return rs

# choose the labelled capacities of the buckets
for bs in subsets(irange(10, 20), size=3):
# find viable ways to use the buckets
for qs in buckets(100, bs):
# largest [was: smallest] bucket must be used twice
if qs[-1] != 2: continue
# output solution
printf("bs={bs} qs={qs}")
```

The interpretation of the puzzle text where there is just a single way to fill the buckets can be implemented at line 13 by only returning the list of candidates if it has a length of 1. But this doesn’t change the answer found.

Like

• Correct, with SubstitutedExpression I end up with 3 options (the third solution would be if the capacity of the smallest bucket is reduced by 1.5 litres).

Like

• #### Jim Randell 8:26 am on 21 May 2022 Permalink | Reply

It has been suggested to me that the intended interpretation of this puzzle is more like this (with {{ changed sections }} in double braces):

A plumber was trying to empty a tank containing 100 litres of water using three buckets, each marked with a different whole number of litres capacity between 10 and 20 litres. {{ He calculated that by completely filling each bucket a number of times, he could exactly empty the tank, but only by using all three buckets. }}

He filled and emptied each bucket the calculated number of times, {{ each bucket being used a different number of times. But when he finished }} the tank still contained 6 litres of water, because the smallest bucket had a dent that reduced its capacity by 3 litres.

What were the marked capacities of the three buckets?

To solve this formulation of the puzzle we can take my program and just move the “different number of times” test (line 10 in the program above is moved to line 18 below):

```from enigma import (irange, subsets, express, seq_all_different as all_different, printf)

# find viable ways to use the buckets
def buckets(t, bs):
rs = list()
for qs in express(t, bs):
# each bucket is used
if 0 in qs: return []
# is viable
rs.append(qs)
return rs

# choose the labelled capacities of the buckets
for bs in subsets(irange(10, 20), size=3):
# find viable ways to use the buckets
for qs in buckets(100, bs):
# the numbers of uses are all different
if not all_different(qs): continue
# smallest bucket must be used twice
if qs != 2: continue
# output solution
printf("bs={bs} qs={qs}")
```

Like

• #### Mark Valentine 12:00 pm on 22 May 2022 Permalink | Reply

I think the text is absolutely fine. Clearly you need three different bucket sizes, where no two (or one) of which can combine to make exactly 100. Then from these triples you apply the condition for the smallest bucket size.

Like

• #### Jim Randell 12:27 pm on 22 May 2022 Permalink | Reply

@Mark: You also need to check that the numbers of uses of each bucket are all different. And where this requirement is placed in the puzzle text makes a difference.

The original puzzle text has no solutions. My revised text does have a unique solution. (And it seems that this revised text corresponds to the intended puzzle).

Like

• #### Mark Valentine 9:00 pm on 22 May 2022 Permalink | Reply

Ok to be fair I didn’t check for uniqueness . Just stopped at a solution. so will defer.

Like

• I don’t see that changing the passages in double braces makes any difference!

Does the clue lie in “but only by using all three buckets” ?
That is to say, no (different) integer multiples of any two undented buckets would sum to 100 litres.

Like

• #### Jim Randell 10:03 am on 21 May 2022 Permalink | Reply

There is a subtle difference between “but only using all three buckets” and “but only using all three buckets, each a different number of times” that stops the puzzle from working in the originally published formulation.

The “using all three buckets” requirement means we can’t use buckets with capacity 10 or 20, as then we could exactly empty the tank using just one of them. Similarly if a collection of buckets includes a pair that can be used to exactly empty the tank then that is also disallowed.

Like

• Yes, but he used the buckets the calculated number of times.

Like

• #### J Slusar 6:55 pm on 21 May 2022 Permalink | Reply

But what is wrong with buckets marked 13, 14 and 15 filling the smallest twice, the middle one once and the larger one 4 times? The total would have been 100, but the reduced capacity of the smaller bucket would mean 6 litres remained in the tank?

Like

• #### Jim Randell 10:01 pm on 21 May 2022 Permalink | Reply

Thanks for the comment.

I think this combination is ruled out by the requirement that “he could exactly empty the tank, but only by using all three buckets and completely filling each bucket a different number of times”.

With (13, 14, 15) there are three ways we can make 100:

100 = 0×13 + 5×14 + 2×15
100 = 1×13 + 3×14 + 3×15
100 = 2×13 + 1×14 + 4×15

The first of these means that you don’t have to use all three buckets, and the second means that you don’t have to use each bucket a different number of times. So the requirement is not met.

Like

• Doesnt work because 5*14 +2*15=100 ie the tank can be emptied with only 2 of the buckets.

Like

• I finally managed to find a program solution, which agrees with Jim’s last posting i.e 3rd posting (21 May 2022).

```
% A Solution in MiniZinc
include "globals.mzn";

int: Tank == 100;   % litres

% Three buckets - capacity ranges in litres
var 10..20:B1; var 10..20:B2; var 10..20:B3;

% Three different size buckets are required
constraint B1 < B2 /\ B2 < B3;

% No of times buckets B1, B2 and B3 are emptied
var 1..10:n1;  var 1..10:n2;  var 1..10:n3;

constraint all_different([n1, n2, n3]);

% Smallest bucket B1 must be emptied twice due to a 3L dent
constraint n1 == 2;

% Tank emptying constraints for one and two buckets
% Tank cannot be emptied with any single bucket
constraint forall(i in 1..10) ( Tank mod (B1 * i) != 0 );
constraint forall(i in 1..10) ( Tank mod (B2 * i) != 0 );
constraint forall(i in 1..10) ( Tank mod (B3 * i) != 0 );

% Buckets B1 and B2 cannot empty tank on their own
constraint forall(i in 1..10, j in 1..10) (
Tank mod (i * B1 + j * B2) != 0);

% Buckets B1 and B3 cannot empty tank on their own
constraint forall(i in 1..10, j in 1..10) (
Tank mod (i * B1 + j * B3) != 0);

% Buckets B2 and B3 cannot empty tank on their own
constraint forall(i in 1..10, j in 1..10) (
Tank mod (i * B2 + j * B3) != 0);

% Empty the tank with three buckets B1, B2 and B3
constraint Tank mod (n1 * B1 + n2 * B2 + n3 * B3) == 0;

solve satisfy;

output [" Capacities of three buckets (B1, B2, B3) = "
++ show([B1, B2, B3 ] )
++ "\n" ++ " No of times each bucket emptied (n1, n2, n3) = "
++ show([n1, n2, n3 ]) ];

```

Like

• To simplify restraints you can use:

```
constraint forall(i in 0..10, j in 0..10, k in 0..10) (
i * B1 + j * B2 + k * B3 != Tank \/ i * j * k > 0);
```

Like

• ## Teaser 3105: Roman primes

Romulus played a game using several identical six-sided dice. Each die face shows a different single-character Roman numeral. He rolled two dice and was able to form a prime number in Roman numerals by arranging the two characters. Romulus rolled more dice and, after each roll, formed a prime number with one more character, rearranging the sequence as needed, until he could no longer form a prime number less than 100. He was using standard notation where a character before another that is 5 or 10 times larger is subtracted from the larger one, e.g., IX = 9.

After playing many games he realised that there were exactly three primes less than 100 that could not occur in any of the sequences.

In decimal notation and in ascending order, what were those prime numbers?

I found two different scenarios that fit the puzzle text, but lead to two different answers. So I have marked the puzzle as flawed.

[teaser3105]

• #### Jim Randell 5:28 pm on 25 March 2022 Permalink | Reply

To represent numbers from 1 to 99 using Roman numerals requires five characters I, V, X, L, C. So we know those must be on the dice. The other symbol is probably D (= 500), which lets us express numbers up to 899 (with sufficient dice; it takes 12 to make 888 = DCCCLXXXVIII).

I’m assuming that Romulus rolls 2 dice, arranges them to make the first prime in the sequence. Then rolls another single die, and arranges the 3 dice (without changing the numerals shown by the first two) to make the second prime, and so on. Rolling a single new die at each step until he is unable to rearrange the dice to make a prime, or he runs out of dice.

Then we can find a scenario where there are three primes that cannot occur in any sequence.

This Python program runs in 51ms.

Run: [ @replit ]

```from enigma import (Primes, int2roman, group, join, multiset, printf)

# primes less than 100
primes = Primes(100)

# record primes by their roman numeral content
d = group(primes, by=(lambda n: join(sorted(int2roman(n)))))

# find length n extensions of ks in d
def extend(d, ks, n):
ss = list(multiset.from_seq(k) for k in ks)
for k in d.keys():
if len(k) == n:
s = multiset.from_seq(k)
if any(s.issuperset(s_) for s_ in ss):
yield k

# generate possible throws with increasing lengths
def generate(d, n=2):
ks = list(k for k in d.keys() if len(k) == n)
while ks:
yield (n, ks)
# find keys that are one longer
n += 1
ks = list(extend(d, ks, n))

ps = set(primes)
for (n, ks) in generate(d, 2):
# and remove those reachable after n dice
for k in ks:
ps.difference_update(d[k])
# we have a solution if there are 3 primes remaining
if len(ps) == 3:
printf("{n} dice -> {ps}", ps=sorted(ps))
```

Solution: The prime numbers are: 5, 37, 83.

This is the solution in the scenario where Romulus has 6 dice, with the symbols I, V, X, L, C, and one other.

5 (= V) only requires 1 die, so cannot be constructed using 2-6 dice.

83 (= LXXXIII) requires 7 dice, so cannot be constructed using 2-6 dice.

37 (= XXXVII) can be constructed using 6 dice, but there is no predecessor prime using 5 dice.

Possible predecessor numbers for 37 are: 27, 32, 34, 46. None of which are prime.

However I was able to find another scenario (see below), where Romulus has more than 6 dice, with the symbols I, V, X, L, and two others, that do not include C.

In this scenario 5 and 37 cannot be constructed (as above), but 83 can be constructed using 7 dice.

However the standard representation of 97 in Roman numerals is XCVII, which cannot be constructed if the symbol C is not available. (In fact none of the numbers in [90, 499] can be constructed with these dice).

So the solution in this scenario is: 5, 37, 97.

It seems that this second scenario is what the setter had in mind (it is the published answer), although it seems less plausible to me.

Perhaps the following would have been a better representation of the intended puzzle:

Romulus found a box containing a large number of identical six-sided dice. Each die face shows a different Latin character, and Romulus found that when he rolled some of the dice he was sometimes able to rearrange them so that the top faces formed a Roman numeral (using standard notation).

He played a game where he rolled two dice and was able to form a prime number by arranging the two characters. He then rolled another die and was able to arrange the three dice to form another prime number. He carried on rolling extra dice (one die each time), until he could no longer arrange the dice to form a prime number less than 100.

After playing many games he realised that there were exactly three primes less than 100 that could not occur in any of the sequences.

In decimal notation and in ascending order, what were those prime numbers?

Like

• #### Robert Brown 7:39 am on 26 March 2022 Permalink | Reply

When the text says ‘after many games’ I assumed that some of these would start with II (=2) and some with XI (=11). Clearly cannot find 5 (V) as it is length 1, but I only have one more prime which cannot be made with one of the two starting pairs.

Like

• #### Jim Randell 8:57 am on 26 March 2022 Permalink | Reply

@Robert: It looks like you are 2/3 of the way to the answer.

There is a scenario that satisfies the wording of the puzzle text, and there are three primes that are not constructible. And each of the three primes is non-constructible for a different reason.

Like

• #### Jim Randell 12:51 pm on 26 March 2022 Permalink | Reply

I think there is potentially an alternative scenario that also gives three non-constructible primes:

If the dice have the symbols I, V, X, L, D, M on them (so not C), then one of the primes is not constructible (using “standard” Roman numerals), no matter how many dice are used.

We can modify the program for this scenario by only considering primes that don’t include C when constructing the dictionary `d`:

```# record constructible primes by their roman numeral content
d = group(primes.irange(1, 89), by=(lambda n: join(sorted(int2roman(n)))))
```

Or here is a version of my code that tries all possible combinations of 6 of the 7 symbols I, V, X, L, C, D, M for the dice [ @replit ], it finds three possibilities corresponding to the two scenarios outlined above.

```from enigma import (Primes, int2roman, group, join, multiset, subsets, printf)

# primes less than 100
primes = Primes(100)

# find length n extensions of ks in d
def extend(d, ks, n):
ss = list(multiset.from_seq(k) for k in ks)
for k in d.keys():
if len(k) == n:
s = multiset.from_seq(k)
if any(s.issuperset(s_) for s_ in ss):
yield k

def generate(d, n=2):
ks = list(k for k in d.keys() if len(k) == n)
while ks:
yield (n, ks)
# find keys that are one longer
n += 1
ks = list(extend(d, ks, n))

# solve the puzzle for allowable symbols
def solve(symbols):

# record primes their roman numeral content
d = group(primes, by=(lambda n: join(sorted(int2roman(n)))))

# remove keys with invalid symbols
d = dict((k, v) for (k, v) in d.items() if symbols.issuperset(k))

ps = set(primes)
for (n, ks) in generate(d, 2):
# remove those reachable after n dice
for k in ks:
ps.difference_update(d[k])
# we have a solution if there are 3 primes remaining
if len(ps) == 3:
printf("{syms}: {n} dice -> {ps}", syms=join(sorted(symbols)), ps=sorted(ps))

# choose 6 symbols for the dice
for syms in subsets('IVXLCDM', size=6, fn=set):
solve(syms)
```

I think I prefer the original scenario given above, where a sufficient number of dice can be used to give the numbers from 1 to 899. A set of dice without C would only be able to go consecutively up to 89 (the next smallest constructible number would be 500). D and M don’t come into play until 400 and 900 respectively.

Like

• #### Jim Randell 9:58 am on 1 April 2022 Permalink | Reply

Depending on the shape of the glyphs used on the dice, it may be possible to use a V on its side to represent C, which would leave only 2 primes non-constructible in this second scenario (unless the number of dice is limited – and then we get the same solution as my first scenario). Like

• I came to the same conclusion as Robert. I feel the setter of this puzzle has played a trick on us, but Jim rumbled it (before he came up with the alternative scenario ). It would have been neater, to my mind, if the puzzle text had stated that there were just two primes less than 100 that could not occur.

Like

• #### Jim Randell 3:58 pm on 26 March 2022 Permalink | Reply

There’s definitely some trickery going on, as what you might expect to be the normal interpretation does not give 3 non-constructible primes.

We would need to have more information about the symbols or number of dice to work out which scenario the setter had in mind.

Like

• ## Teaser 3075: Prime cuts for dinner

From The Sunday Times, 29th August 2021 [link]

Tickets to the club dinner were sequentially numbered 1, 2, …, etc. and every ticket was sold. The number of guests for dinner was the highest common factor of three different two-figure numbers and the lowest common multiple of three different two-figure numbers. There were several dinner tables, each with the same number of seats, couples being seated with friends. The guests on each table added their ticket numbers together and obtained one of two prime numbers, both less than 150, but if I told you the larger prime number you would not be able to determine the other.

What was the larger of the two prime numbers?

[teaser3075]

• #### Jim Randell 7:03 pm on 27 August 2021 Permalink | Reply

This Python program looks for candidate solutions, but doesn’t show that the tickets can be assigned to tables in the required fashion. However there is only one possible answer, so this is not necessary. (However, it is possible to assign tickets in both cases – see [link]).

It runs in 234ms.

Run: [ @replit ]

```from enigma import mgcd, mlcm, subsets, irange, intersect, divisors_pairs, tri, Primes, express, filter_unique, unpack, printf

# generate candidate solutions
def generate():

# primes less than 150
primes = Primes(150)

# look for gcds and lcms of 3 2-digit numbers
(gcds, lcms) = (set(), set())
for ns in subsets(irange(10, 99), size=3):

# consider number of tickets, n
for n in intersect([gcds, lcms]):
# total sum of tickets
t = tri(n)
# consider k tables, with q people per table
for (k, q) in divisors_pairs(n, every=1):
if k < 3 or q < 3: continue

# consider 2 primes, for the ticket sums
for (p1, p2) in subsets(primes, size=2):
# express the total using 2 of the primes
for (q1, q2) in express(t, (p1, p2), min_q=1):
if q1 + q2 == k:
yield (n, t, k, q, p1, p2, q1, q2)

# look for candidate solutions, where p1 is ambiguous by p2
ss = filter_unique(
generate(),
unpack(lambda n, t, k, q, p1, p2, q1, q2: p2),
unpack(lambda n, t, k, q, p1, p2, q1, q2: p1),
)

for (n, t, k, q, p1, p2, q1, q2) in ss.non_unique:
printf("n={n}: t={t}; {k} tables of {q} people; ({p1}, {p2}) -> ({q1}, {q2})")
```

Solution: The larger of the two primes was 109.

There are 30 tickets:

gcd(30, 60, 90) = 30
lcm(10, 15, 30) = 30

And 30 is the only number that satisfies the conditions.

So the sum of the ticket numbers is T(30) = 465.

And the tickets can be arranged into 5 tables of 6 people, to give one of two prime sums for each table as follows:

Table 1: 2, 3, 4, 5, 7, 8; sum = 29
Table 2: 1, 9, 13, 27, 29, 30; sum 109
Table 3: 6, 10, 14, 25, 26, 28; sum = 109
Table 4: 11, 12, 17, 22, 23, 24; sum = 109
Table 5: 15, 16, 18, 19, 20, 21; sum = 109

Table 1: 1, 3, 7, 25, 26, 27; sum = 89
Table 2: 5, 6, 9, 22, 23, 24; sum 89
Table 3: 8, 10, 11, 19, 20, 21; sum = 89
Table 4: 12, 13, 14, 15, 17, 18; sum = 89
Table 5: 2, 4, 16, 28, 29, 30; sum = 109

In each case the larger prime is 109.

And there are many ways to achieve the same sums.

Like

• I programmed this teaser in two stages, first re-using the few lines of Jim’s code to find the intersection of GCD/LCM values to give the number of guests.

The next stage was to examine possible table arrangements and arrangements of two prime numbers to make up the sum of tickets.

I also tested different prime number multipliers e.g 4/1 and 3/2 for the 5 table arrangement and 5/1 and 4/2 for the 6 table arrangement.

```
from itertools import permutations
from enigma import mgcd, mlcm, subsets, irange, Primes

# primes less than 150
primes = Primes(150)

# look for 3 No. 2-digit numbers for gcd and lcm values
gcds, lcms = set(), set()
for ns in subsets(irange(10, 99), size=3):

# Numbers of Guests (N)
N = list(gcds.intersection(lcms))
print('No. of guests = ', N)   # N = 30

# Ticket sum of numbers for N guests
T = N * (N + 1)//2
print('Sum of all ticket numbers = ', T)

# 30 people - possible table arrangements:
# - 5 tables of 6 people or 6 tables of 5 people - two possibilities
# - 2 tables of 15 people or 15 tables of 2 people - not viable
# - 3 tables of 10 people or 10 tables of 3 people - not viable

# try 5 tables of 6 people, using 2 primes to make sum of tickets
# results were found for prime multipliers of 4 and 1
print('Two possible prime values:')
for p1, p2 in permutations(primes, 2):
if 4 * p1 + p2 == T:
print( (max(p1, p2), min(p1, p2)),  end = "  ")

# (149, 79)  (109, 89)  (101, 61)  (103, 53)  (107, 37)  (109, 29)  (113, 13)
# There is only maximum prime i.e. 109, where the other prime could not be known.
# For maximum primes of 149, 101, 103, 107 and 113, the second prime is known.

# try 6 tables of 5 people, using 2 primes make sum of tickets
for p3, p4 in permutations(primes,2):
if 5 * p3 + p4 == T:
print(max(p3, p4), min(p3, p4))
# No solution

# No. of guests =  30
# Sum of all ticket numbers =  465
# Two possible prime values:
# (149, 79)  (109, 89)  (101, 61)  (103, 53)  (107, 37)  (109, 29)  (113, 13)

```

This section of code find the two sets of three two digit numbers used by the setter for the HCF/LCM values in this teaser.

There were 33 numbers in the GCD set of numbers and 25,608 numbers in the LCM set of numbers, with a minimum value of 30 and a maximum value of 941,094. The setter used the minimum LCM value.

```
# The number of guests for dinner was the highest common
# factor of three different two-figure numbers and the
# lowest common multiple of three different two-figure numbers.

# Q. What were these two sets of three digit numbers?

from itertools import combinations

from math import gcd, lcm
for x in combinations(range(10, 100), 3):
a, b, c = x
if gcd(a, b, c) == 30:
print(f"Three 2-digit values for HCF = {a}, {b}, {c}")

for x in combinations(range(10, 100), 3):
d, e, f = x
if lcm(d, e, f) == 30:
print(f"Three 2-digit values for LCM = {d}, {e}, {f}")

# Three 2-digit values for HCF = 30, 60, 90
# Three 2-digit values for LCM = 10, 15, 30
# Therefore, a value of 30 was used for number of guests.

```

Like

• ## Teaser 3069: Fit for purpose

From The Sunday Times, 18th July 2021 [link]

George and Martha bought a new toy for their son Clark. It consisted of a rectangular plastic tray with dimensions 15×16cm and eight plastic rectangles with dimensions 1×2cm, 2×3cm, 3×4cm, 4×5cm, 5×6cm, 6×7cm, 7×8cm and 8×9cm. The rectangles had to be placed inside the tray without any gaps or overlaps. Clark found every possible solution and he noticed that the number of different solutions which could not be rotated or reflected to look like any of the others was the same as his age in years.

How old was Clark?

[teaser3069]

• #### Jim Randell 5:19 pm on 16 July 2021 Permalink | Reply

I reused the code from rectpack.py, originally written for Enigma 1491, and also used in Teaser 2650.

Each solution also appears rotated, reflected, and rotated and reflected, so the total number of solutions found is 4× the answer.

The following Python program runs in 199ms.

Run: [ @replit ]

```from enigma import irange, ediv, printf
from rectpack import pack_tight as pack, output_grid

# width/height of the tray
(X, Y) = (15, 16)

# rectangles
rs = list((x, x + 1) for x in irange(1, 8))

# count the solutions
n = 0
for (i, s) in enumerate(pack(X, Y, rs), start=1):
printf("{i}: {s}")
output_grid(X, Y, s)
printf()
n += 1

printf("age = {x}", x=ediv(n, 4))
```

Solution: Clark was 10.

The 10 solutions arise due to the following 2 packings: The first has 3 (coloured) sub-rectangles that can be flipped over, giving 2×2×2 = 8 packings.

The second has only 1 sub-rectangle, so gives 2 packings.

Like

• #### Jim Randell 6:32 pm on 16 July 2021 Permalink | Reply

And here is an alternate version that calculates a canonical form for each solution, and counts the number of different canonical forms.

```from enigma import irange, printf
from rectpack import pack_tight as pack, output_grid

# width/height of the tray
(X, Y) = (15, 16)

# rectangles
rs = list((x, x + 1) for x in irange(1, 8))

# rotation / reflection
rotate = lambda s: tuple(sorted((X - x - w, Y - y - h, w, h) for (x, y, w, h) in s))
reflect = lambda s: tuple(sorted((X - x - w, y, w, h) for (x, y, w, h) in s))

# canonical form of s
def canonical(s):
s = tuple(sorted(s))
r = rotate(s)
return min(s, r, reflect(s), reflect(r))

# count the canonical forms
ss = list()
for (i, s) in enumerate(pack(X, Y, rs), start=1):
r = canonical(s)
if r not in ss:
ss.append(r)
printf("{i} -> {x}", x=len(ss))
output_grid(X, Y, s)
else:
printf("{i} -> {x}", x=ss.index(r) + 1)
printf()

printf("age = {x}", x=len(ss))
```

Like

• With analysis to place the biggest piece in top left corner.

This program ran in 181ms.

```
from itertools import product

(X, Y) = (15, 16)        # width/height of the tray
M = 9                    # longest side of rectangle

# return grid coordinates (top left, bottom right) where piece w x h will fit
def grid_coords(grid, w, h):
res = []
for i in range(M, X + M):
for j in range(M, Y + M):
if grid[i][j] == 0:
# horizontal and vertical
for k in range(2):
if all(grid[x][y] == 0 for x in range(i, i + h)
for y in range(j, j + w)):
res.append([(i - M, j - M), (i - M + h - 1, j - M + w - 1)])

(w, h) = (h, w)   # mirror
return res

# print grid without borders
def grid_print(grid):
for i, g in enumerate(grid):
if M <= i < Y + M - 1:
print(f"{g[M:-M]}")
print()

# fit k pieces into empty spots in the grid
def fit(r, k, s):
if k == 1:
# check if last piece fits
coords = grid_coords(s, r, r)
if coords:
(tl, rb) = (coords, coords)
for (i, j) in product(range(tl, rb + 1), range(tl, rb + 1)):
s[i + M][j + M] = k
yield [r.copy() for r in s]       # return copy !!
# backtrack
for (i, j) in product(range(tl, rb + 1), range(tl, rb + 1)):
s[i + M][j + M] = 0
else:
(w, h) = r   # pick first remaining piece from list
for tl, rb in grid_coords(s, w, h):
if k == N:
# only allow the biggest piece 9x8 mostly in the top left quadrant
# in order to prevent rotated or reflected versions
#
# if biggest piece is not in the top left corner (not touching (0, 0)):
# - if biggest piece lies vertical then placing the 8x7 piece
#   results in a 9x1 stroke --> impossible
# - if biggest piece lies horizontal there is a stroke 8xa to the left
#   and a stroke 8xb to the left (where a + b = 7)
#   strokes of 8x1, 8x2 or 8x3 are impossible to fill --> impossible

if tl != (0, 0): continue

# update piece in the grid s
for (i, j) in product(range(tl, rb + 1), range(tl, rb + 1)):
s[i + M][j + M] = k

yield from fit(r[1:], k - 1, s)
# backtrack
for (i, j) in product(range(tl, rb + 1), range(tl, rb + 1)):
s[i + M][j + M] = 0

# rectangles (biggest first)
rs = list((x, x + 1) for x in range(8, 0, -1))
N = len(rs)

# initialize grid with borders of size M
grid = [[9 for i in range(Y + 2 * M)] for j in range(X + 2 * M)]
# initialize inner grid to 0
for i in range(X):
for j in range(Y):
grid[i + M][j + M] = 0

# generate solutions
sols = list(fit(rs, N, grid))

print("Clark was", len(sols), "years old. \n\nexample:\n")
grid_print(sols)
```

Like

• ## Teaser 3058: Total resistance

From The Sunday Times, 2nd May 2021 [link] A physics teacher taught the class that resistors connected in serial have a total resistance that is the sum of their resistances while resistors connected in parallel have a total resistance that is the reciprocal of the sum of their reciprocal resistances, as shown in the diagrams. Each pupil was told to take five 35-ohm resistors and combine all five into a network [using a combination of series and/or parallel connections]. Each pupil then had to calculate theoretically and check experimentally the resistance of his or her network. Every network had a different resistance and the number of different resistances was the maximum possible. The total sum of these resistances was a whole number.

How many pupils were there in the class and what was the sum of the resistances?

[teaser3058]

• #### Jim Randell 4:13 pm on 30 April 2021 Permalink | Reply

We can make a recursive function to calculate the set of resistances for a collection of k resistors, combined into a circuit using only serial and parallel connections (and not “bridge”-type circuits).

Any permissible circuit is constructed from the connection of two smaller circuits (i.e. circuits using fewer resistors) either in series or in parallel. And we don’t need to keep track of the layout of the smaller circuits, only their resistance values. (Which neatly eliminates the need to remove duplicate circuits). And we can cache these values to avoid recomputing them repeatedly.

This Python program collects the resistance values of smaller circuits (starting with a single resistor) and combines them to calculate the resistance values of larger circuits. (A unit resistance value is used, which can be multiplied up for circuits consisting of resistors of the same value). It runs in 50ms.

Run: [ @replit ]

```from itertools import product
from enigma import Rational, irange, cached, arg, printf

F = Rational()  # implementation of rationals

# series and parallel combinations
S = lambda x, y: x + y
P = lambda x, y: F(1, F(1, x) + F(1, y)) # = F(x * y, x + y)

# generate arrangements of k unit resistors
@cached
def arrange(k):
# if there is only 1 resistor
if k == 1:
# there is only 1 arrangement
return {1}
else:
# otherwise split the resistors
s = set()
for i in irange(1, k // 2):
# consider the sub-arrangements
for (x, y) in product(arrange(i), arrange(k - i)):
# and combine them in series and parallel
s.update((S(x, y), P(x, y)))
return s

# calculate the different resistances of 5 resistors
k = arg(5, 0, int)
R = arg(35, 1, int)
s = arrange(k)
printf("[k={k} R={R}] {n} different values; total = {t}", n=len(s), t=sum(s) * R)
```

Solution: There were 22 pupils in the class. The total sum of the constructed resistance values was 1052.

See also: OEIS A048211 [ @oeis ]. I have used my program to verify the sequence up to k = 21, but beyond that requires more memory than my machine has.

The sequence OEIS A000084 [ @oeis ] gives the total number of different series/parallel circuit configurations that can be constructed, but some of them may have the same resistance value.

For example the following combinations of 4 resistors give the same value:

(R + R) | (R + R) = R
(R | R) + (R | R) = R

For k = 5 there are 24 different circuits that can be constructed, but only 22 different resistance values.

The sequence OEIS A337516 [ @oeis ] also includes “bridge”-type circuits (the first of which appears at k = 5) and “fork”-type circuits (which appear at k = 7).

Like

• #### Tony Brooke-Taylor 7:27 pm on 30 April 2021 Permalink | Reply

Jim, I tried to test my manual solution using your code and can’t reconcile your result for k=3. Have you included cases where there can be 1 resistor in parallel?

Like

• #### Tony Brooke-Taylor 7:43 pm on 30 April 2021 Permalink | Reply

Sorry, I knew I should have thought a bit harder. Of course I realised my error as soon as I submitted my reply…

Like

• #### Jim Randell 7:53 pm on 30 April 2021 Permalink | Reply

@Tony:

With 1 resistor we have 1 way: {R}

With 2 resistors they can be in series or parallel, 2 ways: {R+R, R|R } = { 2R, (1/2)R }

With 3 resistors we can combine a group of 1 resistors with a group of two resistors in 4 ways: {R+(R + R), R+(R|R), R|(R + R), R|(R|R) } = { 3R, (2/3)R, (1/3)R, (3/2)R }.

It is interesting to note that if we can make a resistance of r with a circuit of k unit resistors, then we can also make a resistance of 1/r (by interchanging series and parallel connections).

Like

• if bridging is allowed then my answer is 23 pupils and total resistance value = 1087.
if bridging is not allowed 22 pupils = 1052.
(the bridge network is 35 ohms)

Like

• #### Jim Randell 5:24 pm on 2 May 2021 Permalink | Reply

I think this puzzle is only concerned with networks that are composed from series and parallel connections (as that is all the children are told about, so they wouldn’t know how to calculate the theoretical resistance of other types of circuits). I have now clarified the puzzle text on this point.

(I try not to directly reveal the solution to prize puzzles until after it is closed to entries).

Like

• #### Hugh Casement 1:31 pm on 9 May 2021 Permalink | Reply

>>
For k = 5 there are 24 different circuits that can be constructed,
but only 22 different resistance values.
<<

2R and ½R are each duplicated, where R = 35 ohms in this case.

With four resistors it's just R that's duplicated, as Jim said in his original post on 30 Apr.
Add an extra resistor to each of those circuits, once in series and once in parallel,
and we have the duplicates for k = 5.

Sorry if I'm stating the obvious!

Like

• ## Teaser 3021: Field for thought

From The Sunday Times, 16th August 2020 [link]

Farmer Giles had a rectangular field bordered by four fences that was 55 hectares in size. He divided the field into three by planting two hedges, from the mid-point of two fences to two corners of the field. He then planted two more hedges, from the mid-point of two fences to two corners of the field. All four hedges were straight, each starting at a different fence and finishing at a different corner.

What was the area of the largest field when the four hedges had been planted?

[teaser3021]

• #### Jim Randell 10:24 pm on 14 August 2020 Permalink | Reply

The x and y co-ordinates of the intersections of the hedges helpfully divide the edges of the rectangle into equal divisions.

The area of the central quadrilateral is then easily calculated.

Solution: The central field has an area of 11 hectares. In the first diagram, each of the four coloured triangular areas has an area of xy/5, so the central region also has an area of xy/5.

Another way to think of it is that there are five quadrilaterals each identical to the central one, but four of them have had bits sliced off them, and then the sliced off bits have been repositioned to make the original rectangle.

This gives a handy practical construction achievable using folding and straight edge to divide a rectangle into 5 equal strips (or a 5×5 grid of identical smaller rectangles).

This is a bit like Routh’s Theorem (see: Enigma 1313Enigma 320Enigma 1076, Teaser 2865) but for a rectangle instead of a triangle.

In general, if the the lines are drawn from a corner to a point a fraction f along a side we can determine the area of the central quadrilateral (as a fraction of the overall parallelogram) as:

A = (1 − f)² / (1 + f²)

In the case of f = 1/2 we get:

A = (1/2)² / (1 + (1/2)²) = (1/4) / (5/4) = 1/5

Like

• ## Teaser 2993: Baker’s weights

From The Sunday Times, 2nd February 2020 [link]

A baker’s apprentice was given a 1kg bag of flour, scales and weights, each engraved with a different whole number of grams. He was told to separately weigh out portions of flour weighing 1g, 2g, 3g, and so on up to a certain weight, by combining weights on one side of the scales. He realised that he couldn’t do this if there were fewer weights, and the largest weight was the maximum possible for this number of weights, so he was surprised to find after one of these weighings that the whole bag had been weighed out. Upon investigation, he discovered that some of the weights weighed 1g more than their engraved weight. If I told you how many of the weights were too heavy, you would be able to work out what they all were.

What were the actual weights (in ascending order)?

[teaser2993]

• #### Jim Randell 8:24 am on 1 February 2020 Permalink | Reply

When I first read the puzzle it didn’t seem to make any sense, or have a solution.

So I set about investigating the parts of the text that are unambiguous:

(a) The apprentice has a set of weights, some of which are mislabelled (weighing 1g more than labelled).

(b) The apprentice is weighing amounts of 1g, 2g, 3g, … until at some point he unexpectedly has used up exactly 1000g of flour.

With k weights we can make (2^k − 1) different non-empty collections of weights. Using weights that are powers of 2 (i.e. 1g, 2g, 4g, 8g, …) allows us to weigh all the amounts between 1 and (2^k − 1).

So we can start weighing out increasing amounts, look at what weights have been used and look at when a collection of mislabelled weights would bring the total amount weighed out to exactly 1000g.

This Python program runs in 77ms.

Run: [ @repl.it ]

```from enigma import multiset, irange, inf, subsets, nsplit, ordered, filter_unique, unpack, printf

# record possible solutions:
# (<number of weighings>, <number of mislabelled weights>, <sequence of weights>)
ss = list()

# record the labels of the weights used
s = multiset()

# consider possible number of weighings, and total expected amount weighed out
t = 0
for n in irange(1, inf):
t += n
if t > 1000: break
# calculate the required weights
ws = list(2 ** i for (i, m) in enumerate(reversed(nsplit(n, base=2))) if m)
printf("{n} -> {t}; {ws}")

s.update_from_seq(ws)

# now consider a subset of the weights that actually weigh 1g more than labelled
for xs in subsets(s.keys(), min_size=1):
# the total extra weight being...
x = sum(s[x] for x in xs)
# does this bring the total to exactly 1kg?
if t + x == 1000:
k = len(xs)
printf(" -> {xs}; +{x}; {k}")
ss.append((n, k, ordered(*(w + (w in xs) for w in s.keys()))))

# find solutions unique by the number of mislabelled weights
(ss, _) = filter_unique(ss, unpack(lambda n, k, ws: k))

# output solutions
for (n, k, ws) in ss:
printf("n={n} k={k} ws={ws}")
```

Solution: The actual weights were: 2g, 3g, 5g, 9g, 17g, 32g.

So the apprentice has a set of six weights, labelled: 1g, 2g, 4g, 8g, 16g, 32g. Which, if correct, could be used to weigh any integer amount between 1g and 63g.

However, five of the weights are mislabelled. The 1g, 2g, 4g, 8g, 16g weights all weigh 1g more than their label suggests.

After the apprentice has weighed out amounts corresponding to 1g, 2g, 3g, …, 42g using the weights he would expect to have used 903g of flour, but with this set of weights he has actually used a total of 1000g of flour.

The apprentice may have set out to make weights up to 42g (expecting to use 903g of flour), up to 43g (expecting to use 946g of flour), or up to 44g (expecting to use 990g of flour). For higher amounts 1000g of flour would not be enough to complete the task.

There are also potential solutions when apprentice gets to 43g. With the set of six weights he would expect to have weighed out 946g of flour. But there are four combinations of 3 mislabelled weights, which would bring the total to exactly 1000g. (If the (1, 4, 32), (1, 8, 32), (2, 4, 32) or (2, 8, 32) weights are mislabelled).

But we are told that if we knew the number of mislabelled weights we could work out the actual weights in the set. So we must be dealing with the case where 5 of the weights are mislabelled.

The most reasonable scenario seems to be that apprentice was given a 1kg bag of flour and a set of 6 weights, labelled: 1g, 2g, 4g, 8g, 16g, 32g, and asked to weigh out amounts from 1g to 44g.

The total amount to be weighed out is T(44) = 990g, so he would be expecting to have 10g of flour left at the end.

However, after one of the weighings he has used up exactly 1000g of flour (assuming the bag of flour was actually 1000g in the first place).

There 5 ways this can happen:

After weighing 42g using weights (2, 3, 5, 9, 17, 32) [5 mislabelled weights]
After weighing 43g using weights (2, 2, 5, 8, 16, 33) [3 mislabelled weights]
After weighing 43g using weights (2, 2, 4, 9, 16, 33) [3 mislabelled weights]
After weighing 43g using weights (1, 3, 5, 8, 16, 33) [3 mislabelled weights]
After weighing 43g using weights (1, 3, 4, 9, 16, 33) [3 mislabelled weights]

We are told that if we knew the number of mislabelled weights we could work out which they were, so we must be dealing with the first situation with 5 mislabelled weights.

Like

• #### Robert Brown 8:45 pm on 1 February 2020 Permalink | Reply

He’s told to weigh portions up to a certain weight, must be <=44 as that uses 990g of flour. Binary set of weights goes up to 63g, so some of the weights could be smaller. Text says 'the largest weight was max possible for this number of weights' – I took this to mean there's a weight engraved 32g, but others seem to think it means the largest portion was the max possible for this number of weights. We all get the same answer, but using my method I didn't need to be told how many of the weights were too heavy. Does your program incorporate this?

Like

• #### Jim Randell 8:59 pm on 1 February 2020 Permalink | Reply

@Robert: I originally thought “the largest weight was the maximum possible for this number of weights” would refer to the largest portion that the apprentice was to weigh out. So it would have to be 31g (with 5 weights) or 63g (with 6 weights), but neither of these can give a solution.

In the end I assumed that the set of weights used was labelled as powers of 2 (i.e. 1g, 2g, 4g, 8g, …), and then used the program to look for amounts where we would expect (if the weights were correctly labelled) to have weighed out a cumulative amount less than 1000g, but if some of the weights were 1g heavier than labelled the cumulative amount is actually exactly 1000g.

I found one set with 5 mislabelled weights where this happens, and four sets with 3 mislabelled weights.

The puzzle text says if we knew the number of mislabelled weights we would know what the actual set of weights was, so the answer we want is the the set with 5 mislabelled weights.

I think the wording of the puzzle could have been clearer.

Like

• #### Robert Brown 3:49 pm on 3 February 2020 Permalink | Reply

Jim: I agree with everything that you say, but Brian Gladman seems to think “the largest weight etc” refers to the “certain weight” that the apprentice was told to use as a limit. He then thinks it’s reasonable to set this to 63g. But the person giving instructions to the apprentice would know this was impossible, as even with correct weight labels, the flour would run out after he weighed 44 portions. Of course we don’t know if that person was aware that some of the weights were wrong, which muddies the waters a bit. But Brian’s telling me that I’m effectively solving a different problem, but as far as I can see, it’s the same problem that you have solved.
In fact, the four sets with 3 mislabelled weights occur at weighing 43, while the the set with 5 mislabelled weights occur at weighing 42. So I discounted weighing 43, which means that I didn’t need to be told the number of mislabelled weights.

Because the weights we used can give up to 63g, I looked to see what alternatives could give every 1g step up to 44, and found 323 ways to do this, (if the 32g weight is omitted). Beyond my abilities to analyse all of these to see if there’s an alternative solution!

Like

• #### Jim Randell 9:46 am on 4 February 2020 Permalink | Reply

I think that “the largest weight was the maximum possible for this number of weights” is a roundabout way of saying that that the weights are powers of 2. In a set of 6 (correctly labelled) weights this would mean that the largest weight was 32g, so the remaining 5 weights have to be able to weigh 1g-31g, which means they also have to be powers of 2.

Using a set of weights that is powers of 2, means that there is only one combination of weights that makes up any specific amount, so when looking for how many times each weight is used in the weighings there is a single answer. Otherwise we may have to consider multiple different ways to make up a specific amount, which could give us different actual weights. So I think this would be a much harder problem (and maybe not have a unique solution).

If we take “the largest weight was the maximum possible for this number of weights” to mean that the largest amount the apprentice was asked to weigh out was the largest possible for the number of weights, then if the set has 6 weights he would have been asked to weight out amounts up to 63g. This also implies that the set of weights is a “powers of 2” set. But also means that the apprentice was being set an impossible task. (Although there is a long tradition of sending apprentices on futile or impossible tasks, and as it turns out he has been given a doctored set of weights, so his task does indeed turn out to be impossible).

I think the most reasonable interpretation is that the apprentice was given a set of 6 weights, labelled 1g, 2g, 4g, 8g, 16g, 32g and asked to weigh out amounts up to 42g, 43g or 44g (but we don’t know which). Each of these would appear to be an achievable task.

As the apprentice weighs out the amounts he finds that the entire bag has been used up after one of the weighings. This is possible in one way after weighing out the 42g portion, and 4 ways after weighing out the 43g portion. We are told that if we knew the number of mislabelled weights, then we could work out which ones they were, so I think we need to take all these cases into account.

So I think the most reasonable scenario was that the apprentice was asked to weigh out amounts up to 44g, a task which initially looks possible, but depending on the actual set of weights means you would run out of flour after weighing the 42g or 43g portion, making it impossible to complete the task.

Of the 5 possible sets of weights that lead to exactly 1000g of flour being used before we get to the 44g weight, one of them involves 5 weights being doctored and four of them involved 3 of the weights being doctored. So the answer we want is the set with 5 weights.

Like

• ## Teaser 2894: Time duality

From The Sunday Times, 11th March 2018 [link]

After a good breakfast, Seb decided on 40 winks. He noted the time on his digital clock as he dozed off. When he woke up a little later that day, not fully alert, he saw the display reflected in a mirror and was amazed by how long he seemed to have slept. This was in fact 10 times the length of his nap. Next day, a similar thing happened: he fell asleep at the same time and slept a little less, but when he woke, the mirror led him to believe he had slept for 20 times as long as he had. (All times were whole numbers of minutes after midnight).

At what time did he fall asleep?

[teaser2894]

• #### Jim Randell 9:16 am on 7 August 2019 Permalink | Reply

We can find multiple solutions to this puzzle, depending on how the clock works.

The program examines the following three scenarios for a digital clock consisting of standard 7-segment digits, where the digits 0, 1 and 8 appear the same when mirrored, and the digits 2 and 5 appear as each other when mirrored.

Scenario 1: 24 hour clock, always displays 4 digits, reads from 00:00 – 23:59.

Scenario 2: 24 hour clock, leading zeros are suppressed on the hours, and no clear hour/minute separator, reads from 0:00 – 23:59.

Scenario 3: 12 hour clock, leading zeros are suppressed on the hours, and no clear hour/minute separator, reads from 12:00 – 11:59.

It runs in 125ms.

Run: [ @repl.it ]

```from itertools import product
from collections import defaultdict
from enigma import arg, irange, nsplit, div, sprintf, printf

# digit reflections
X = None
#           0  1  2  3  4  5  6  7  8  9
reflect = [ 0, 1, 5, X, X, 2, X, X, 8, X ]

# format time t as hh:mm
def fmt(t, hours=24):
k = 0
while t < 0:
k -= 1
t += hours * 60
while t > hours * 60:
k += 1
t -= hours * 60
(h, m) = divmod(t, 60)
return sprintf("{h:02d}:{m:02d} [{k:+d}]")

# solve using digits function <digits>
def solve(digits, hours=24):
# record results by start time (in minutes), 10x or 20x
rs = defaultdict(lambda: defaultdict(list))

# map display digits to possible times
m = defaultdict(list)
for t in irange(0, 24 * 60 - 1):
m[digits(t)].append(t)

# find sequences that have a reverse sequence
for (s, t1s) in m.items():
r = tuple(reflect[d] for d in s[::-1])
if None in r or r == s: continue
if r in m:
t2s = m[r]

for (t1, t2) in product(t1s, t2s):
if t1 == t2: continue
while t2 < t1: t2 += 24 * 60
d = t2 - t1

# find differences that give 9x or 19y
x = div(d, 9)
if x:
t0 = t1 - x
printf("[{t1} | {t2} = {d} min (9x {x}m), t0={t0}]", t1=fmt(t1, hours), t2=fmt(t2, hours), t0=fmt(t0, hours))
rs[t0].append((t1, t2))
y = div(d, 19)
if y:
t0 = t1 - y
printf("[{t1} | {t2} = {d} min (19x {y}m), t0={t0}]", t1=fmt(t1, hours), t2=fmt(t2, hours), t0=fmt(t0, hours))
rs[t0].append((t1, t2))

# output solutions
for (t0, d) in rs.items():
for ((t1a, t2a), (t1b, t2b)) in product(d, d):
if t1b < t1a:
(ft0, ft1a, ft2a, ft1b, ft2b) = (fmt(x, hours) for x in (t0, t1a, t2a, t1b, t2b))
printf("10x = {ft0} - {ft1a} | {ft2a} / 20x = {ft0} - {ft1b} | {ft2b}")

# digits displayed for time t in the different scenarios:

#  four digits, 24 hours: 00:00 - 23:59
def digits1(t):
(h, m) = divmod(t, 60)
return nsplit(h % 24, 2) + nsplit(m, 2)

#  three or four digits, 24 hours: 0:00 - 23:59, no clear separator
def digits2(t):
(h, m) = divmod(t, 60)
return nsplit(h % 24) + nsplit(m, 2)

#  three or four digits, 12 hours: 0:00 - 11:59, no clear separator
def digits3(t):
(h, m) = divmod(t, 60)
return nsplit(h % 12 or 12) + nsplit(m, 2)

types = {
'1': [ digits1, "[type 1] 00:00 - 23:59", 24 ],
'2': [ digits2, "[type 2] 0:00 - 23:59", 24 ],
'3': [ digits3, "[type 3] 12:00 - 11:59", 12 ],
}

cmd = arg("123", 0)

for k in sorted(types.keys()):
if k not in cmd: continue
(fn, t, h) = types[k]
printf("{t}")
solve(fn, hours=h)
printf()
```

We find the following solutions:

Scenario 1: 24 hour clock, always displays 4 digits, reads from 00:00 – 23:59.

This is probably the most reasonable expectation of the clock’s behaviour without further explanation.

Day 1: The nap starts at 09:41 and finishes after 74m at 10:55. The mirrored display reads 22:01 corresponding to a nap of 740m (= 10×74m).
Day 2: The nap starts at 09:41 and finishes after 34m at 10:15. The mirrored display reads 21:01 corresponding to a nap of 680m (= 20×34m).

Day 1: The nap starts at 09:21 and finishes after 119m at 11:20. The mirrored display reads 05:11 corresponding to a nap of 1190m (= 10×119m).
Day 2: The nap starts at 09:21 and finishes after 59m at 10:20. The mirrored display reads 05:01 corresponding to a nap of 1180m (= 20×59m).

But in both these solutions the second nap is less than half the length of the first nap, so it is a bit odd to say he slept “a little less” than the previous day.

Scenario 2: 24 hour clock, leading zeros are suppressed on the hours, and no clear hour/minute separator, reads from 0:00 – 23:59.

The 09:41 nap works the same, but the 09:21 nap does not as 10:20 when mirrored does not correspond to a displayable time.

Day 1: The nap starts at 09:41 and finishes after 74m at 10:55. The mirrored display reads 22:01 corresponding to a nap of 740m (= 10×74m).
Day 2: The nap starts at 09:41 and finishes after 34m at 10:15. The mirrored display reads 21:01 corresponding to a nap of 680m (= 20×34m).

This scenario has a unique solution, but the problem remains that the second nap is less than half the length of the first nap.

Scenario 3: 12 hour clock, leading zeros are suppressed on the hours, and no clear hour/minute separator, reads from 12:00 – 11:59.

Day 1: The nap starts at 07:18 and finishes after 64m at 08:22. The mirrored display reads “558” corresponding to 17:58 and a nap of 640m (= 10×64m).
Day 2: The nap starts at 07:18 and finished after 57m at 08:15. The mirrored display reads “218” corresponding to 02:18 and a nap of 1140m (= 20×57m).

And as it is a 12 hour clock this all works shifted on 12 hours, although perhaps 7:18pm is a little late to be having breakfast.

The problem here is that on day two when seeing the clock reading 2:18 Seb would probably think he had slept for 7 hours, not for 19 hours. However this is the best solution for sleeping “a little less” on the second day, and the puzzle text does say Seb was not fully alert when he read the clock.

Out of all these scenarios the one that best fits the puzzle text is Scenario 3:

On the first day, Seb has an early breakfast, and starts his snooze at 7:18am, and wakes up at 8:22am, having slept for 64m, but reads the time as 5:58, and believes he has slept until 5:58pm, which is 640m.

On the second day, Seb again starts his snooze at 7:18am, and wakes at 8:15am, having slept for 57m (which is only 7m shorter than the previous day). He reads the time as 2:18, and believes he has slept until 2:18am the following day, which is 1140m.

This gives us a solution to the puzzle that Seb fell asleep on both days at 7:18am.

It is possible that the phrase “all times were whole numbers of minutes after midnight”, is meant to indicate that all the times mentioned (including the false mirrored times) are all supposed to fall within the same 24 hour day, in which case the 9:41am solution in Scenario 1 or Scenario 2 remain, and give a unique solution of 9:41am. This may be the setters intended solution.

But as there are multiple possible answers I have marked this puzzle as “flawed“.

Liked by 1 person

• ## Teaser 2926: Coins of Obscura

From The Sunday Times, 21st October 2018 [link]

George and Martha were on holiday in Obscura where coins are circular with radii equal to their whole number value in scurats. They had coffees and George took out some loose change. He placed one 10 scurat and two 15 scurat coins on the table so that each coin touched the other two and a smaller coin between them that touched all three. He then placed a fifth coin on top of these four which exactly covered them and the total value of the five coins was exactly enough to pay the bill.

How much was the coffee bill?

[teaser2926]

• #### Jim Randell 8:02 am on 5 April 2019 Permalink | Reply

I think by “exactly covered” the setter means that the fifth coin was the smallest possible circle that would cover the original three coins.

If you’ve encountered “Soddy Circles” the fourth and fifth coins correspond to the inner and outer Soddy circles formed from the first three coins.

There is a (relatively) straightforward expression that can be used to calculate the radii of these circles (see: [ Descartes Theorem ]).

Here is a useful reference for Soddy Circles: [ link ]

This Python program runs in 89ms.

Run: [ @replit ]

```from enigma import (is_square, div, printf)

# calculate the radius of the inner and outer Soddy circles
# (we are only interested in integer solutions)
def soddy(r1, r2, r3):
x = r1 * r2 * r3
y = is_square(x * (r1 + r2 + r3))
if y is None: return (None, None)
z = r1 * r2 + r1 * r3 + r2 * r3
return (div(x, 2 * y + z), div(x, 2 * y - z))

# initial parameters
(r1, r2, r3) = (10, 15, 15)

# the radii of the Soddy circles
(r, R) = soddy(r1, r2, r3)
assert not (r is None or R is None)
printf("[r1={r1} r2={r2} r3={r3} -> r={r} R={R}]")

t = r1 + r2 + r3 + r + R
printf("total = {t}")
```

Solution: The bill came to 72 scurats.

The additional coins have values of 2 and 30.

Here is a diagram. The original coins are shown in black, the inner and outer Soddy Circles (corresponding to the fourth and fifth coins) are shown in red: Like

c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r