Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

Complete solutions in C++, Python & Java — with step-by-step mathematical explanations

All Problems

Problem 392: Enmeshed Unit Circle

View on Project Euler

Project 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

  1. Problem page: https://projecteuler.net/problem=392
  2. Unit circle: Wikipedia — Unit circle
  3. Bisection method: Wikipedia — Bisection method
  4. Shooting method: Wikipedia — Shooting method
  5. Riemann sum: Wikipedia — Riemann sum

Mathematical approach · C++ solution · Python solution · Java solution

Previous: Problem 391 · All Project Euler solutions · Next: Problem 393

Need help with a problem? Ask me! 💡
e
✦ Euler GLM 5.2
Hi! I'm Euler. Ask me anything about Project Euler problems, math concepts, or solution approaches! 🧮