Teaser 3063: Pie by five
From The Sunday Times, 6th June 2021 [link] [link]
We had a delicious pie, rectangular and measuring 20 centimetres along the top and 13 centimetres in the other direction. We divided it into five pieces of equal area, using five straight cuts radiating from one internal point. This internal point was rather off centre, in the top left-hand quarter, although the distances from the left and top sides were both a whole number of centimetres. The points where the cuts met the edges were also whole numbers of centimetres along the edges; one edge had two cuts meeting it, and the other three edges had one each.
How far was the internal point from the left and top sides, and how far along the four sides (starting at the top) did the cuts reach the edges (measured clockwise along the edges)?
[teaser3063]
Jim Randell 9:59 pm on 4 June 2021 Permalink |
Each portion has an area equal to one fifth of the whole pie.
The portion between the two cuts on the same side is composed of a single triangle (with, as it turns out, its base along the bottom edge). The remaining portions are composed of two adjacent triangles, with their bases on adjacent edges.
Using the top left corner of the pie as the origin, we can consider integer (x, y) co-ordinates for the starting point of the cuts (in the top left quadrant of the pie). We can then consider 2 integer marks on the bottom that give a triangular slice with one fifth the area of the pie, and the marks on the other edges can then be determined.
This Python program runs in 54ms.
Run: [ @replit ]
from itertools import product from enigma import (Rational, irange, divf, printf) Q = Rational() # is rational q an integer? as_int = lambda q: (q.numerator if q.denominator == 1 else None) # dimensions of the rectangle (X, Y) = (20, 13) # area of each portion A = Q(X * Y, 5) printf("[X={X} Y={Y}; A={A}]") # calculate area of a triangle with base b and height h area = lambda b, h: Q(b * h, 2) # calculate base of triangle with area A and height h base = lambda A, h: Q(2 * A, h) # find solutions with cuts starting at (x, y) def solve(x, y): # look for the portion composed of 1 triangle: # bottom marks, (a, Y), (b, Y); distance z (= b - a) apart z = as_int(base(A, Y - y)) if z is None: return for a in irange(1, X - z - 1): b = a + z # remaining bottom triangles left and right (B1, C1) = (area(a, Y - y), area(X - b, Y - y)) # left mark, (0, c) c = as_int(Y - base(A - B1, x)) if c is None or not (0 < c < Y): continue # right mark (X, d) d = as_int(Y - base(A - C1, X - x)) if d is None or not (0 < d < Y): continue # top mark (e, 0) e = as_int(base(A - area(c, x), y)) if e is None or not (0 < e < X): continue printf("x={x} y={y} -> bottom: {a}, {b}; left: {c}; right: {d}; top: {e}") # choose a position for the start of the cuts for (x, y) in product(irange(1, divf(X - 1, 2)), irange(1, divf(Y - 1, 2))): solve(x, y)Solution: The cuts started from a point 8 cm in from the left edge and 5 cm in from the top edge. The end of cuts were: top = 16 cm from the left; right = 7 cm from the top; bottom = 4 cm and 17 cm from the right; left = 10 cm from the bottom.
A similar approach can be used to look for situations with 2 cuts on other edges, but these yield no viable solutions.
The idea of splitting each portion into triangles can be used to show that for any regular polygon, portions (cut from the centre) with equal amounts of the perimeter have equal size.
LikeLike
Frits 10:18 am on 5 June 2021 Permalink |
@Jim, very clever. I am looking forward to next week (or earlier) when you explain the method you have used.
LikeLike
Frits 9:48 am on 5 June 2021 Permalink |
Having done most of the work myself.
# x = distance internal point from left edge # y = distance internal point from top edge # a = distance top left-hand corner to meeting point on left edge # b = distance top left-hand corner to meeting point on top edge # c = distance top right-hand corner to meeting point on right edge # d = distance bottom left-hand corner to 2nd meeting point on bottom edge # e = distance bottom left-hand corner to 1st meeting point on bottom edge # if we make a triangle with the bottom edge (points e and d) # then the following formula can be derived: (d - e)(13 - y) = 104 = 8 * 13 # # only one value for y is possible. # with this derived value of y we calculate the areas of the 5 slices # and end up with 5 equations and 6 variables # # (13 - a)x = 8(13 - e) (A) # 5b + ax = 104 (B) # (20 - x)c = 4 + 5b (C) # 13x + 8d + 20c - cx = 316 (D) # d = 13 + e (E) for a in range(1, 7): # (not disclosing y) for x in range(1, 10): # consider equation B ax = a * x if ax % 10 not in {4, 9}: continue b = (104 - ax) // 5 # meeting point with edge is not in the corner if b > 19: continue # consider equation A y = 13 * x - ax if y % 8: continue e = 13 - y // 8 d = 13 + e # consider equation C (c, r) = divmod(4 + 5 * b, 20 - x) if r: continue # check equation D if 13 * x + 8 * d + 20 * c - c * x != 316: continue # use bogus formula for derived value y (not disclosing y) print(f"{x=} y={x-a}, top: {b} right: {c} bottom: {e=} {d=} left: {a}")LikeLike
Tony Brooke-Taylor 7:53 am on 7 June 2021 Permalink |
My approach was similar to yours Frits, but I could not satisfy myself by general reasoning that the two cuts had to be on the bottom edge as opposed to the right-hand edge. I therefore tested for the triangle to be on the right-hand edge but this did not produce a valid solution. Therefore the triangle must be on the bottom edge and there is only one solution.
I got formulae similar to yours by considering parallelograms with missing triangles. Jim’s solution is much more elegant because it divides all the areas into triangles.
LikeLike
Jim Randell 9:31 am on 7 June 2021 Permalink |
@Tony: I did start by considering the two cuts on different edges, but it turned out they had to be on the bottom.
As my program didn’t have a neat way to try the alternates, I just removed the dead paths from my program.
I’ve put a more complete program up as
teaser3063x.pyon replit.from itertools import product from enigma import (Rational, irange, divf, printf) Q = Rational() # is rational q an integer? as_int = lambda q: (q.numerator if q.denominator == 1 else None) # dimensions of the rectangle (X, Y) = (20, 13) # area of each portion A = Q(X * Y, 5) printf("[X={X} Y={Y}; A={A}]") # calculate area of a triangle with base b and height h area = lambda b, h: Q(b * h, 2) # calculate base of triangle with area A and height h base = lambda A, h: Q(2 * A, h) # find solutions with cuts starting at (x, y) def solve(x, y): # look for the portion composed of 1 triangle: # top marks, distance z apart z = as_int(base(A, y)) if z is not None: for a in irange(1, X - z - 1): b = a + z printf("x={x} y={y} -> top: {a}, {b}; ...") # bottom marks, distance z apart z = as_int(base(A, Y - y)) if z is not None: for a in irange(1, X - z - 1): b = a + z # remaining bottom sections of slices left and right (B1, C1) = (area(a, Y - y), area(X - b, Y - y)) # left mark c = as_int(Y - base(A - B1, x)) if c is None or not (0 < c < Y): continue # right mark d = as_int(Y - base(A - C1, X - x)) if d is None or not (0 < d < Y): continue # top mark e = as_int(base(A - area(c, x), y)) if e is None or not (0 < e < X): continue printf("x={x} y={y} -> bottom: {a}, {b}; left: {c}; right: {d}; top: {e}") # left marks, distance z apart z = as_int(base(A, x)) if z is not None: for a in irange(1, Y - z - 1): b = a + z printf("x={x} y={y} -> left: {a}, {b}; ...") # right marks, distance z apart z = as_int(base(A, X - x)) if z is not None: for a in irange(1, Y - z - 1): b = a + z # remaining sections of right slices above and below (B1, C1) = (area(a, X - x), area(Y - b, X - x)) # top mark c = as_int(X - base(A - B1, Y - y)) if c is None or not (0 < c < X): continue # bottom mark d = as_int(X - base(A - C1, Y - y)) if d is None or not (0 < d < X): continue printf("x={x} y={y} -> right: {a}, {b}; top={c}; bottom={d}; ...") # choose a position for the start of the cuts for (x, y) in product(irange(1, divf(X - 1, 2)), irange(1, divf(Y - 1, 2))): solve(x, y)LikeLike