On this page
[Link] https://www.acmicpc.net/problem/7869
Intersection area
Let the circle centers be and , their radii be , and the distance between centers be . The intersection area depends on how the circles meet:
- If , they are disjoint or externally tangent, so the intersection area is .
- If , one circle lies inside the other or they are internally tangent. The intersection is the smaller disk, with area . This also handles coincident centers (), including equal circles, without dividing by .
- Otherwise, the circles partially overlap and their boundaries intersect at two points.
For partial overlap, draw radii to either intersection point. In the triangle formed by the two centers and that point, the cosine law gives the half-angles at the centers:
Each circle contributes a sector with central angle . Subtracting the isosceles triangle inside that sector leaves a circular segment of area . Adding the two segments gives the lens area:
Floating-point rounding can move a cosine-law value slightly outside its mathematical range, so clamp each acos argument to [-1, 1]. The containment and disjointness cases are tested first; consequently the partial-overlap formulas never divide by zero and tangencies are handled by the boundary cases.
C++17 implementation
The algorithm uses constant time and constant extra space, for both.
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <iostream>
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
double x1, y1, r1, x2, y2, r2;
std::cin >> x1 >> y1 >> r1 >> x2 >> y2 >> r2;
const double dx = x1 - x2;
const double dy = y1 - y2;
const double d = std::hypot(dx, dy);
const double pi = std::acos(-1.0);
double area;
if (d >= r1 + r2) {
area = 0.0;
} else if (d <= std::abs(r1 - r2)) {
const double radius = std::min(r1, r2);
area = pi * radius * radius;
} else {
const double d2 = d * d;
const double r1_2 = r1 * r1;
const double r2_2 = r2 * r2;
const double cos1 = std::clamp((d2 + r1_2 - r2_2) / (2.0 * d * r1), -1.0, 1.0);
const double cos2 = std::clamp((d2 + r2_2 - r1_2) / (2.0 * d * r2), -1.0, 1.0);
const double theta1 = std::acos(cos1);
const double theta2 = std::acos(cos2);
area = r1_2 * theta1 + r2_2 * theta2
- 0.5 * r1_2 * std::sin(2.0 * theta1)
- 0.5 * r2_2 * std::sin(2.0 * theta2);
}
std::cout << std::fixed << std::setprecision(3) << area << '\n';
return 0;
}