Problem 392: Enmeshed Unit Circle
View on Project EulerProject Euler Problem 392 Solution
EulerSolve provides an optimized solution for Project Euler Problem 392, Enmeshed Unit Circle, with C++, Python, Java, and a step-by-step mathematical explanation.
Problem Summary For even \(N\), the implementation models the red region as a symmetric staircase built around the unit circle. By symmetry, the four quadrants contribute the same amount, so it is enough to optimize a single quadrant and multiply by \(4\). If \(m=N/2\), the numerical task is to choose \(m\) interior breakpoints on the quarter-circle so that this staircase area is as small as possible. Mathematical Approach 1. Reduce the geometry to one quadrant In the first quadrant the circle is the graph $f(x)=\sqrt{1-x^2}, \qquad 0 \le x \le 1.$ Choose breakpoints $0=x_0 \lt x_1 \lt \cdots \lt x_m \lt x_{m+1}=1,$ and set \(y_i=f(x_i)\). On each interval \([x_i,x_{i+1}]\), the staircase uses the constant height \(y_i\). Therefore the quadrant contribution is $Q(x_1,\dots,x_m)=\sum_{i=0}^{m}(x_{i+1}-x_i)f(x_i).$ The full red area is then $A_N=4Q(x_1,\dots,x_m).$ This is exactly the quantity accumulated by the code after the optimal breakpoints have been found. 2. Derive the optimality recurrence The key point is that the solver is not using an arbitrary mesh. It chooses the breakpoints so that \(Q\) is stationary with respect to every interior variable \(x_k\). Only two summands depend on \(x_k\): $ (x_k-x_{k-1})f(x_{k-1}) \qquad \text{and} \qquad (x_{k+1}-x_k)f(x_k)....
Detailed mathematical approach
Problem Summary
For even \(N\), the implementation models the red region as a symmetric staircase built around the unit circle. By symmetry, the four quadrants contribute the same amount, so it is enough to optimize a single quadrant and multiply by \(4\). If \(m=N/2\), the numerical task is to choose \(m\) interior breakpoints on the quarter-circle so that this staircase area is as small as possible.
Mathematical Approach
1. Reduce the geometry to one quadrant
In the first quadrant the circle is the graph
$f(x)=\sqrt{1-x^2}, \qquad 0 \le x \le 1.$
Choose breakpoints
$0=x_0 \lt x_1 \lt \cdots \lt x_m \lt x_{m+1}=1,$
and set \(y_i=f(x_i)\). On each interval \([x_i,x_{i+1}]\), the staircase uses the constant height \(y_i\). Therefore the quadrant contribution is
$Q(x_1,\dots,x_m)=\sum_{i=0}^{m}(x_{i+1}-x_i)f(x_i).$
The full red area is then
$A_N=4Q(x_1,\dots,x_m).$
This is exactly the quantity accumulated by the code after the optimal breakpoints have been found.
2. Derive the optimality recurrence
The key point is that the solver is not using an arbitrary mesh. It chooses the breakpoints so that \(Q\) is stationary with respect to every interior variable \(x_k\). Only two summands depend on \(x_k\):
$ (x_k-x_{k-1})f(x_{k-1}) \qquad \text{and} \qquad (x_{k+1}-x_k)f(x_k). $
Differentiating \(Q\) with respect to \(x_k\) gives
$\frac{\partial Q}{\partial x_k}=f(x_{k-1})-f(x_k)+(x_{k+1}-x_k)f'(x_k).$
For the unit circle,
$f'(x)=\frac{-x}{\sqrt{1-x^2}}=-\frac{x}{f(x)}.$
Setting \(\frac{\partial Q}{\partial x_k}=0\) and rearranging yields
$\boxed{x_{k+1}=x_k+\frac{(f(x_{k-1})-f(x_k))f(x_k)}{x_k}}, \qquad 1 \le k \le m.$
This boxed identity is the exact recurrence implemented in the C++, Python, and Java solutions.
3. Why one unknown is enough: the shooting formulation
Once \(x_1\) is fixed, the recurrence determines \(x_2,x_3,\dots,x_{m+1}\) one after another. That reduces the original \(m\)-variable minimization problem to a one-variable boundary condition:
$x_{m+1}=1.$
The implementations encode this through the residual function
$R(x_1)=x_{m+1}(x_1)-1.$
Then a shooting step becomes: guess \(x_1\), build the whole sequence, inspect the sign of \(R(x_1)\), and refine the guess. The code brackets \(x_1\) inside \((10^{-18},0.999999999999)\) and performs 260 bisection iterations. If a trial leaves the admissible region or produces a non-finite value, the build is rejected and the residual is treated as \(+\infty\), which safely pushes the search back toward valid values.
4. Evaluate the area after solving the boundary condition
After bisection, the sequence is rebuilt from the final \(x_1\). The code then forces \(x_{m+1}=1\) exactly to eliminate tiny floating-point boundary drift. With the final sequence in hand, it computes
$Q=\sum_{i=0}^{m}(x_{i+1}-x_i)f(x_i),$
and returns
$A_N=4Q.$
So the numerical work has two clean phases: first satisfy the optimality equations with the endpoint condition, then evaluate the resulting staircase area.
5. Checkpoints and numerical interpretation
For \(N=2\) we have \(m=1\). The optimum occurs at
$x_1=\frac{1}{\sqrt{2}}, \qquad f(x_1)=\frac{1}{\sqrt{2}},$
which gives
$A_2=4\left(x_1+(1-x_1)f(x_1)\right)=4\sqrt{2}-2.$
This is the first checkpoint used in the C++ program.
For \(N=10\), shooting produces the breakpoints
$0,\ 0.3800728430,\ 0.5627007923,\ 0.7071067812,\ 0.8266606428,\ 0.9249565579,\ 1,$
and the total area
$A_{10}\approx 3.3469640797.$
This is the second checkpoint in the C++ file. With the default input \(N=400\), the implementations output
$A_{400}\approx 3.1486734435.$
How the Code Works
f(x) evaluates the quarter-circle height. build_sequence stores the breakpoints and applies the recurrence step by step. shooting_residual returns \(R(x_1)\). solve_breakpoints performs the fixed-count bisection loop and then enforces the right endpoint numerically. Finally, minimal_red_area accumulates the strip areas and multiplies by \(4\). The Python and Java files are direct translations of the same method; the C++ version additionally checks \(N=2\) and \(N=10\) before printing the default \(N=400\) answer.
Complexity Analysis
Let \(m=N/2\). One call to build_sequence computes \(m+1\) new values, so it costs \(O(m)\) time and \(O(m)\) memory. Bisection performs a fixed 260 residual evaluations, hence the implemented runtime is \(O(260m)=O(N)\). If the iteration count is written symbolically as \(B\), the method is \(O(BN)\) time and \(O(N)\) memory.
References
- Problem page: https://projecteuler.net/problem=392
- Unit circle: Wikipedia — Unit circle
- Bisection method: Wikipedia — Bisection method
- Shooting method: Wikipedia — Shooting method
- Riemann sum: Wikipedia — Riemann sum