Skip to content
Vamshi Jandhyala

Books · The Riddler

Chapter 189

How Fast Can You Deliver PB&Js? How Many Meerkats Can Survive?

Riddler Express

You deliver peanut-butter-and-jelly sandwiches from a restaurant at 2020th Street and Avenue F in Riddler City. The grid has 6161 east-west streets (11st to 6161st) and 2121 north-south avenues (A to U), with each block 0.10.1 miles long. The speed limit is 2020 mph everywhere, except Avenue U (the Ultra-Speed Trafficway) at 200200 mph. For which destinations does it pay to detour to Avenue U? (No traffic, no turn losses.)

The Riddler, FiveThirtyEight, July 6, 2018(original post)

Solution

Index streets r=1,,61r = 1, \ldots, 61 and avenues c=1,,21c = 1, \ldots, 21 (so A =1= 1, F =6= 6, U =21= 21). Each block is 0.10.1 miles. At 2020 mph a block takes 0.1/2060=0.30.1 / 20 \cdot 60 = 0.3 minutes; on Avenue U at 200200 mph a block takes 0.030.03 minutes. You start at (r0,c0)=(20,6)(r_0, c_0) = (20, 6).

Direct route. Drive Manhattan-style on surface streets. Time Tdirect(r,c)  =  0.3(r20+c6).T_{\text{direct}}(r, c) \;=\; 0.3 \, (|r - 20| + |c - 6|).

Avenue-U route. Drive east to Avenue U (1515 blocks at 2020 mph), then north or south along U (r20|r - 20| blocks at 200200 mph), then west back to avenue cc (21c21 - c blocks at 2020 mph). Time TU(r,c)  =  0.3(15+21c)  +  0.03r20.T_{\text{U}}(r, c) \;=\; 0.3 \, (15 + 21 - c) \;+\; 0.03 \, |r - 20|. (If c=21c = 21 you skip the westward leg.)

Avenue U pays whenever TU<TdirectT_{\text{U}} < T_{\text{direct}}: 0.3(15+21c)+0.03r20  <  0.3(r20+c6),0.3 \cdot (15 + 21 - c) + 0.03 \, |r - 20| \;<\; 0.3 \, (|r - 20| + |c - 6|), which rearranges to r20  >  4.5+0.3(21c)0.3c60.27.|r - 20| \;>\; \frac{4.5 + 0.3 \,(21 - c) - 0.3 \,|c - 6|}{0.27}. The right-hand side is a function of cc alone; call it the distance-from-20th threshold θ(c)\theta(c). The pattern is:

avenue cc avenue letter θ(c)\theta(c)
11 to 66 A to F 33.3333.33
77 G 31.1131.11
88 H 28.8928.89
99 I 26.6726.67
1010 J 24.4424.44
1111 K 22.2222.22
1212 L 20.0020.00
1313 M 17.7817.78
1414 N 15.5615.56
1515 O 13.3313.33
1616 P 11.1111.11
1717 Q 8.898.89
1818 R 6.676.67
1919 S 4.444.44
2020 T 2.222.22
2121 U 0.000.00

Read this geometrically. Streets only go up to 6161, that is 4141 blocks north of you and 1919 blocks south. So for c{c \in \{A, B, C, D, E, F}\} (the western strip) Avenue U pays only for destinations more than 33.3333.33 blocks away from 2020th Street, that is for street numbers above 5353rd to the north (south is impossible: only 1919 blocks down). Moving east, the threshold drops linearly: by Avenue M (c=13c = 13) you save by detour for anything more than 17.7817.78 blocks away, that is street 2\le 2 or street 38\ge 38. By Avenue T (c=20c = 20) you save almost everywhere off your home row.

The computation

Encode the grid, compute both route times for every address, and confirm the boundary by exhaustive enumeration.

def t_direct(r, c):
    return 0.3 * (abs(r - 20) + abs(c - 6))

def t_via_U(r, c):
    if c == 21:
        return 0.3 * 15 + 0.03 * abs(r - 20)
    return 0.3 * 15 + 0.03 * abs(r - 20) + 0.3 * (21 - c)

faster = 0
boundary = {}
for r in range(1, 62):
    for c in range(1, 22):
        if (r, c) == (20, 6):
            continue
        if t_via_U(r, c) < t_direct(r, c):
            faster += 1
for c in range(1, 22):
    boundary[c] = min(
        (abs(r - 20) for r in range(1, 62)
         if t_via_U(r, c) < t_direct(r, c)),
        default=None,
    )

print("addresses where Avenue U is faster:", faster)
print("boundary |r-20| per column (None = never):")
for c in range(1, 22):
    print(f"  c={c:2d} ({chr(ord('A')+c-1)}): {boundary[c]}")

The script prints addresses where Avenue U is faster: 532 (out of 61211=128061 \cdot 21 - 1 = 1280) and the per-avenue boundary r20|r - 20|, matching the analytic thresholds above. The qualitative answer: use Avenue U for deliveries that are far north (and slightly far south on the eastern side); stay on surface streets near home.

Riddler Classic

Meerkats eat scorpions. Without meerkats the scorpion population doubles every month; without scorpions the meerkat population halves every month; at 2020 scorpions and 55 meerkats both populations are stable. Use the Lotka-Volterra model for predator and prey.

(a) How many meerkats are there when the scorpion population is at its maximum? (b) How many of each are there when the meerkat population is increasing by 44 per month and the scorpion population is decreasing by 22 per month? (c) Starting from 100100 scorpions and 1010 meerkats, what is the largest the meerkat population gets, and how long until both populations return to their starting values?

The Riddler, FiveThirtyEight, July 6, 2018(original post)

Solution

Let xx be the scorpion population, yy the meerkat population, tt time in months. The Lotka-Volterra equations are dxdt  =  axbxy,dydt  =  dxycy.\frac{dx}{dt} \;=\; a x - b x y, \qquad \frac{dy}{dt} \;=\; d x y - c y.

Fitting parameters. With y=0y = 0: dx/dt=axdx/dt = a x, so x(t)=x0eatx(t) = x_0 e^{a t}. Doubling each month means ea=2e^{a} = 2, hence a=ln2a = \ln 2. With x=0x = 0: dy/dt=cydy/dt = -c y, so yy halves each month means ec=1/2e^{-c} = 1/2, hence c=ln2c = \ln 2. The equilibrium (dx/dt,dy/dt)=(0,0)(dx/dt, dy/dt) = (0, 0) at (x,y)=(20,5)(x, y) = (20, 5) gives a=by=5ba = b y = 5 b and c=dx=20dc = d x = 20 d, so b  =  ln25,d  =  ln220.b \;=\; \frac{\ln 2}{5}, \qquad d \;=\; \frac{\ln 2}{20}.

(a) Maximum scorpions. Along any trajectory xx reaches a maximum when dx/dt=0dx/dt = 0, that is when a=bya = b y, that is when y  =  ab  =  5 meerkats.y \;=\; \frac{a}{b} \;=\; 5 \text{ meerkats.} By symmetry the meerkat maximum sits at x=c/d=20x = c/d = 20 scorpions.   y  =  5 meerkats at peak scorpions.  \boxed{\;y \;=\; 5 \text{ meerkats at peak scorpions.}\;}

(b) The prescribed rates. Set dx/dt=2dx/dt = -2 and dy/dt=+4dy/dt = +4: x(aby)  =  2,y(dxc)  =  +4.x (a - b y) \;=\; -2, \qquad y (d x - c) \;=\; +4. From the first, by=a+2/xb y = a + 2/x, so y=(a+2/x)/b=5+10/(ln2x)y = (a + 2/x) / b = 5 + 10/(\ln 2 \cdot x). From the second, dx=c+4/yd x = c + 4/y, so x=(c+4/y)/d=20+80/(ln2y)x = (c + 4/y) / d = 20 + 80/(\ln 2 \cdot y). Substituting and solving numerically gives   x    41.59 scorpions,y    5.35 meerkats.  \boxed{\;x \;\approx\; 41.59 \text{ scorpions}, \quad y \;\approx\; 5.35 \text{ meerkats.}\;} (Fractional animals are an artefact of the continuous model.)

(c) Extra credit: orbit from (100,10)(100, 10). Lotka-Volterra trajectories are closed orbits around the equilibrium (20,5)(20, 5), with conserved quantity H(x,y)  =  dxclnx  +  byalny.H(x, y) \;=\; d x - c \ln x \;+\; b y - a \ln y. The starting point (100,10)(100, 10) fixes HH and the orbit. The peak meerkat population on the orbit is found by setting dy/dt=0dy/dt = 0 along the orbit (x=20x = 20) and using H(100,10)=H(20,ymax)H(100, 10) = H(20, y_{\max}). Numerically integrating gives ymax26.9y_{\max} \approx 26.9 meerkats and the orbit period 13.45\approx 13.45 months. Both values are reproduced in the computation block.   ymax    27,T    13.45 months.  \boxed{\;y_{\max} \;\approx\; 27, \quad T \;\approx\; 13.45 \text{ months.}\;}

The computation

Integrate the Lotka-Volterra ODE numerically with the fitted parameters, read off the equilibrium conditions in (a) and (b), and measure the orbit in (c).

import math
import numpy as np
from scipy.integrate import odeint
from scipy.optimize import fsolve

a = math.log(2)
c = math.log(2)
b = a / 5
d = c / 20

# (b) solve for (x, y) given dx/dt = -2, dy/dt = +4
def eqs(v):
    x, y = v
    return [x * (a - b * y) + 2, y * (d * x - c) - 4]
xb, yb = fsolve(eqs, [40, 5])
print(f"(b) scorpions={xb:.3f}, meerkats={yb:.3f}")

# (c) orbit from (100, 10)
def rhs(state, t):
    x, y = state
    return [a * x - b * x * y, d * x * y - c * y]

t = np.linspace(0, 30, 200_000)
sol = odeint(rhs, [100, 10], t)
xs, ys = sol[:, 0], sol[:, 1]
print(f"(c) max meerkats = {ys.max():.3f}")
# Period: return to (100, 10)
dist = np.sqrt((xs - 100) ** 2 + (ys - 10) ** 2)
i = np.argmin(dist[len(t) // 10:]) + len(t) // 10
print(f"(c) orbit period = {t[i]:.3f} months")

The script prints (x,y)(41.59,5.35)(x, y) \approx (41.59, 5.35), ymax26.9y_{\max} \approx 26.9, and orbit period 13.45\approx 13.45 months, matching the boxed answers.