Library · The Fiddler: Solutions · Chapter 125
Can You Fairly Cut the Birthday Cake?
You and two friends share one rectangular birthday cake, inches long and inches wide, with frosting all along its edge. You want to cut it fairly: each of you gets the same area of cake and the same length of frosted edge. You will do it by choosing a single point inside the cake and making three straight cuts from that point out to the edge. Describe a way to do this. (The three pieces need not have the same perimeter, only the same share of the cake’s original edge.)
The Fiddler, Zach Wissner-Gross, March 1, 2024(original post)
The official solution appeared in the post of March 8, 2024 and describes, among others, the cut from given below. The Extra Credit half of that post is paywalled, so the area of the locus is my own. It agrees with the value that solver Emilie Mitchell derived, as reported in Tom Keith’s published solution notes.
Solution
Put the cake on coordinates with corners , , and , and call the centre of the cuts . The edge is inches long and the cake has area square inches, so each person needs inches of edge and square inches of cake.
One fact does all the work. A piece is the region between two neighbouring cuts, and it splits into triangles with apex , one for each stretch of the edge that the piece owns. A triangle with apex whose base is a stretch of length on a side at distance from has area . So the sum running over the sides the piece touches, with the length of that side it owns. The distances from to the four sides are (bottom), (right), (top) and (left).
A clean fair cut now drops out. Put on the vertical midline, at , and cut to the two bottom corners and to the middle of the top edge, . The bottom triangle owns the whole bottom edge, inches of frosting, and its area is . Each of the other two pieces owns one short side ( inches) and half of the top ( inches), so inches each, and by the left-right symmetry they have equal areas. All three areas are equal once the triangle has a third of the cake: , so . This is the point in the figure below. It is far from the only answer, and that is what the Extra Credit is about.
The computation
The program checks the cut from the definitions. It measures positions round the edge anticlockwise from the origin, so the cut points , and sit at , and . For each piece it walks the edge from one cut point to the next, collecting the corners it passes, builds the piece as a polygon with apex , and finds its area by the shoelace formula. The frosting is the distance walked.
from fractions import Fraction as Fr
def pos(s): # point at distance s round the edge
s %= 60
if s <= 20: return (s, 0)
if s <= 30: return (20, s - 20)
if s <= 50: return (50 - s, 10)
return (0, 60 - s)
def pieces(P, cuts): # cuts: edge positions, increasing
out = []
for a, b in zip(cuts, cuts[1:] + [cuts[0] + 60]):
turns = [c for c in (20, 30, 50, 60, 80, 90) if a < c < b]
poly = [P, pos(a)] + [pos(c) for c in turns] + [pos(b)]
area = abs(sum(u[0]*v[1] - u[1]*v[0] for u, v in
zip(poly, poly[1:] + poly[:1]))) / 2
out.append((area, b - a))
return out
for area, frosting in pieces((Fr(10), Fr(20, 3)), [0, 20, 40]):
print(area, frosting)
It prints
200/3 20
200/3 20
200/3 20
Each piece has a third of the area and a third of the frosting.
Extra Credit
The points from which a fair cut can be made form a closed curve. What is the area inside it?
Solution
First, the frosting. Each piece owns the stretch of edge between its two cut points, so the three cut points must be exactly inches apart round the edge. Describe them by the position of one of them, measured round the edge from ; the others are at and . Moving on by just relabels the same three points, so every fair cut has exactly one description with .
Next, the area, for . The cut points are on the bottom, right and top sides. The piece from to owns of the bottom and of the right side; the piece from to owns of the right side and of the top. By the area fact, fairness asks for and then the third piece has the remaining third automatically. These are two straight-line equations in and , and their determinant works out to , which is never zero. So each gives exactly one point . Solving, and measuring from the centre of the cake by writing , and , gives
Fractions of this shape are the tangent half-angle formulas in disguise. Substitute , so that : That is an arc of an ellipse centred at , with horizontal semi-axis and vertical semi-axis . At the ends, and the arc reaches ; in between it bulges left to . So this half of the locus is the part of the ellipse that lies to the left of the line .
For no new work is needed. Reflecting the cake in its vertical midline turns a fair cut into a fair cut, and it turns the cut points , , into , , , which is the description with parameter , between and . So the other half of the locus is the mirror image: the part of the ellipse centred at lying to the right of . The two arcs meet at , and together they bound the overlap of the two ellipses, a lens shape (shaded in the figure).
The lens is two equal caps, each cut off an ellipse by a line at distance from its centre. Squash the ellipse vertically by the factor and it becomes a circle of radius , cut by a line at distance , which cuts off a segment with angle at the centre and area . Stretching back multiplies areas by . So
The computation
The program finds the fair points without the algebra above. For each of evenly spaced values of it places the cuts at , and and asks for the point at which the first two pieces, measured with pieces from The computation above, each have area . A piece’s area changes linearly as moves, so three trial points determine it exactly, and the program solves for . It then checks, at a sample of the cuts, that all three pieces are fair, that every point lies inside the cake, and finds the area of the closed path through the points with the shoelace formula.
def fair_point(t):
cuts = [t, t + 20, t + 40]
A = lambda P: [a for a, _ in pieces(P, cuts)[:2]]
a0, ax, ay = A((0, 0)), A((1, 0)), A((0, 1))
m = [[ax[i] - a0[i], ay[i] - a0[i]] for i in (0, 1)]
r = [200/3 - a0[0], 200/3 - a0[1]]
det = m[0][0]*m[1][1] - m[0][1]*m[1][0]
return ((r[0]*m[1][1] - m[0][1]*r[1]) / det,
(m[0][0]*r[1] - r[0]*m[1][0]) / det)
n = 20_000
path = [fair_point(20 * k / n) for k in range(n)]
fair = []
for k in range(0, n, 500):
t = 20 * k / n
for a, f in pieces(path[k], [t, t + 20, t + 40]):
fair += [abs(a - 200/3) < 1e-9, f == 20]
inside = all(0 < x < 20 and 0 < y < 10 for x, y in path)
area = abs(sum(u[0]*v[1] - u[1]*v[0] for u, v in
zip(path, path[1:] + path[:1]))) / 2
print("sampled cuts all fair:", all(fair))
print("every point inside the cake:", inside)
print(f"area inside the locus: {area:.4f}")
It prints
sampled cuts all fair: True
every point inside the cake: True
area inside the locus: 7.8800
which matches .