Iterative Circle Packing
Three unit circles are packed inside a larger circle such that each is tangent to the other two and to the outer circle. In the first iteration, we fill each of the initial curvilinear triangular g...
Problem Statement
This archive keeps the full statement, math, and original media on the page.
Three circles of equal radius are placed inside a larger circle such that each pair of circles is tangent to one another and the inner circles do not overlap. There are four uncovered "gaps" which are to be filled iteratively with more tangent circles.

At each iteration, a maximally sized circle is placed in each gap, which creates more gaps for the next iteration. After \(3\) iterations (pictured), there are \(108\) gaps and the fraction of the area which is not covered by circles is \(0.06790342\), rounded to eight decimal places.
What fraction of the area is not covered by circles after \(10\) iterations?
Give your answer rounded to eight decimal places using the format x.xxxxxxxx .
Problem 199: Iterative Circle Packing
Mathematical Foundation
Theorem 1. (Descartes’ Circle Theorem.) Given four mutually tangent circles with curvatures (where curvature , negative for a circle containing the others internally), the following relation holds:
Proof. Let the four circles have centers and radii . For mutually externally tangent circles, . The theorem follows from the algebraic identity obtained by eliminating the center coordinates from these distance equations. Specifically, writing the tangency conditions as a system and applying the quadratic formula in the complex plane (the Descartes Circle Theorem can be proven via the complex Descartes theorem , but the curvature relation follows from the real part). A direct algebraic proof uses Heron’s formula and the cosine rule applied to the triangle of centers.
Lemma 1. (Fourth Curvature Formula.) Given three mutually tangent circles with curvatures , the curvature of the fourth mutually tangent circle (the one fitting in the interstice) is:
Proof. Solving the Descartes equation for :
Expand: where and .
Rearranging: .
By the quadratic formula: .
Now .
So (taking the root for the smaller circle, i.e., larger curvature).
Theorem 2. (Outer Circle Radius.) Three mutually tangent unit circles () inscribed in a larger circle have the outer circle radius:
Proof. The centers of the three unit circles form an equilateral triangle with side length (since each pair is tangent). The circumradius of this triangle is . The outer circle must pass through points at distance (the unit radius) beyond each center, so .
Lemma 2. (Initial Configuration.) The curvature of the outer circle is (negative for internal tangency). The initial curvilinear gaps are:
- 3 outer gaps with bounding curvatures .
- 1 inner gap with bounding curvatures .
Proof. By symmetry, the three outer gaps are equivalent (each bounded by two unit circles and the outer circle). The inner gap is bounded by all three unit circles.
Theorem 3. (Recursive Gap Splitting.) When a circle of curvature is inscribed in a gap bounded by circles of curvatures , three new gaps are created with bounding curvatures , , and .
Proof. The new circle is tangent to all three bounding circles. It divides the original curvilinear triangle into three smaller curvilinear triangles, each bounded by two of the original circles and the new circle.
Editorial
Three unit circles inside an outer circle, iteratively packed for 10 iterations. Find fraction of outer circle area not covered. We initial gaps: 3 outer + 1 inner. We then initial covered area: 3 unit circles. Finally, iterate over iter from 1 to iterations.
Pseudocode
Initial gaps: 3 outer + 1 inner
Initial covered area: 3 unit circles
for iter from 1 to iterations
Complexity Analysis
- Time: Each iteration triples the number of gaps. Starting with 4 gaps, after iterations there are gaps. Total gaps processed: . For : gap operations. Total: .
- Space: to store the current set of gaps. For : gap triples.
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#include <bits/stdc++.h>
using namespace std;
int main() {
// Three unit circles (curvature 1) inside an outer circle
// Outer circle radius R = 1 + 2/sqrt(3)
double R = 1.0 + 2.0 / sqrt(3.0);
double k_outer = -1.0 / R;
// Initial gaps:
// 3 outer gaps: (k_outer, 1, 1)
// 1 inner gap: (1, 1, 1)
// Each gap is a triple of curvatures
// We use Descartes' theorem: k4 = k1+k2+k3 + 2*sqrt(k1*k2+k2*k3+k3*k1)
double total_area = 3.0 * M_PI; // three unit circles
// Use a list of gap triples
vector<tuple<double, double, double>> gaps;
// 3 outer gaps
for (int i = 0; i < 3; i++)
gaps.push_back({k_outer, 1.0, 1.0});
// 1 inner gap
gaps.push_back({1.0, 1.0, 1.0});
for (int iter = 0; iter < 10; iter++) {
vector<tuple<double, double, double>> new_gaps;
for (auto& [a, b, c] : gaps) {
double k_new = a + b + c + 2.0 * sqrt(a * b + b * c + c * a);
total_area += M_PI / (k_new * k_new);
new_gaps.push_back({a, b, k_new});
new_gaps.push_back({a, c, k_new});
new_gaps.push_back({b, c, k_new});
}
gaps = move(new_gaps);
}
double outer_area = M_PI * R * R;
double fraction = 1.0 - total_area / outer_area;
cout << fixed << setprecision(8) << fraction << endl;
return 0;
}
"""
Problem 199: Iterative Circle Packing
Three unit circles inside an outer circle, iteratively packed for 10 iterations.
Find fraction of outer circle area not covered.
"""
import math
def main():
# Outer circle radius
R = 1.0 + 2.0 / math.sqrt(3.0)
k_outer = -1.0 / R
# Total area of packed circles (starting with 3 unit circles)
total_area = 3.0 * math.pi
# Initial gaps as curvature triples
# 3 outer gaps: (k_outer, 1, 1)
# 1 inner gap: (1, 1, 1)
gaps = [(k_outer, 1.0, 1.0)] * 3 + [(1.0, 1.0, 1.0)]
for iteration in range(10):
new_gaps = []
for a, b, c in gaps:
# Descartes' circle theorem
k_new = a + b + c + 2.0 * math.sqrt(a*b + b*c + c*a)
total_area += math.pi / (k_new * k_new)
new_gaps.append((a, b, k_new))
new_gaps.append((a, c, k_new))
new_gaps.append((b, c, k_new))
gaps = new_gaps
outer_area = math.pi * R * R
fraction = 1.0 - total_area / outer_area
print(f"{fraction:.8f}")