主题链接: https://codeforces.com/problemset/problem/600/D
对于这个问题,我在测试28上的答案是错误的,可能看起来像这样:
正确答案:119256.95877838134765625000
我的答案:120502.639190673828125
我猜这是由计算精度引起的,但我没有证据。也许算法本身有问题,请指出。
算法思路:
对于任何给定的两个圆,为了简化计算,我们可以将坐标原点平移到其中一个圆的中心,然后通过旋转将另一个圆旋转到x轴。为了计算圆的交集区域,在之前和之后是等价的,最后形成了一个紫色的圆和一个红色的圆。实际上,最终的交集面积等于两个扇形面积之和减去中间菱形的面积(下图,水平轴x,垂直轴y)。但在此之前,我们必须先计算两个圆的交点。
第一个圆的中心在开始时的坐标: 。第二个圆的中心在开始时的坐标: 。
一系列变换后,第一个圆的中心坐标为: 。
一系列变换后,第二个圆的中心坐标为: 。
.
两个圆的方程被结合:
分别是第一个和第二个圆的半径,因此:
我们可以使用扇形面积公式:。 ,。在这里,弧度值的正负会有问题(如下两个图),但可以证明它们可以被吸收在最终结果中。
最终结果是两个弧形面积之和减去中间菱形的面积。
我的代码:
# define MY_PI 3.14159265358979323846
using namespace std;
typedef long double ld;
ld pow2(ld x){return x * x;}
int main()
{
cout.precision(25);
ld x1, y1, r1, x2, y2, r2; // (x1, y1) is the center point of the circle, r1 is the radius of the circle, the other is similar.
cin >> x1 >> y1 >> r1 >> x2 >> y2 >> r2;
ld c = sqrt(pow2(x2 - x1) + pow2(y2 - y1));
if(r1 + r2 < c) // when r1+r2 < c, there is no intersection
{
cout << 0 << endl;
return 0;
}
if((max(r1, r2) - min(r1, r2)) >= c) // one circle is inside the other circle.
{
cout << MY_PI * pow2(min(r1, r2)) << endl;
return 0;
}
ld x = (pow2(r1) - pow2(r2)) / (2 * c) + c * 0.5;
ld y = sqrt(pow2(r1) - pow2(x));
ld angle1 = 2.0 * acos(x / r1);
ld angle2 = 2.0 * acos((c - x) / r2);
ld ar1 = angle1 * pow2(r1) * 0.5;
ld ar2 = angle2 * pow2(r2) * 0.5;
ld res = ar1 + ar2 - y * c;
cout << res << endl;
return 0;
}