题解
需要考虑几种情况:
在求三角形面积的时候有两种方法:
不过我试了所有方法仍然有一个点WA了,已经用while(1)实验出问题是出在交点在两圆心同侧的情况了。可能是精度问题。
后来学到了一种更为简单的方法,明天发题解。
代码:
2ms,256kB
90 分 (WA一点)
#include<cstdio>
#include<iostream>
#include<cmath>
#include<vector>
#include<algorithm>
using namespace std;
struct Point {
double x, y;
Point(double x=0, double y=0):x(x),y(y) {}
}p1, p2;
typedef Point Vector;
Vector operator + (Vector A, Vector B) { return Vector(A.x+B.x, A.y+B.y); }
Vector operator - (Vector A, Vector B) { return Vector(A.x-B.x, A.y-B.y); }
Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); }
Vector operator / (Vector A, double p) { return Vector(A.x/p, A.y/p); }
bool operator < (const Vector& a, const Vector& b) {
return a.x < b.x || (a.x == b.x && a.y < b.y);
}
const double eps = 1e-10;
int dcmp(double x) {
if(fabs(x) < eps) return 0; else return x < 0 ? -1 : 1;
}
double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; }
double Length(Vector A) { return sqrt(Dot(A, A)); }
double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); }
double Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; }
double Area2(Point A, Point B, Point C) { return Cross(B-A, C-A); }
bool operator == (const Vector& a, const Vector& b) {
return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0;
}
const double PI = acos(double(-1));
struct Circle {
Point c;
double r;
Point point(double a) {
return Point(c.x + cos(a)*r, c.y + sin(a)*r);
}
double S() { return PI*r*r; }
}C1, C2;
double angle(Vector v) { return atan2(v.y, v.x); }
int getCircleCircleIntersection() {
double d = Length(C1.c - C2.c);
if(dcmp(d) == 0) {
if(dcmp(C1.r-C2.r) == 0) return -1;
return 0;
}
if(dcmp(C1.r+C2.r-d) < 0) return 0;
if(dcmp(fabs(C1.r-C2.r)-d > 0)) return 0;
double a = angle(C2.c-C1.c);
double da = acos((C1.r*C1.r + d*d - C2.r*C2.r) / (2*C1.r*d));
p1 = C1.point(a-da), p2 = C1.point(a+da);
return p1 == p2 ? 1 : 2;
}
double Area(double a, double b, double c) {
double p = (a+b+c) / 2.0;
return sqrt(p*(p-a)*(p-b)*(p-c));
}
int main() {
cin >> C1.c.x >> C1.c.y >> C1.r >> C2.c.x >> C2.c.y >> C2.r;
int c = getCircleCircleIntersection();
double d = sqrt((C1.c.x-C2.c.x)*(C1.c.x-C2.c.x) + (C1.c.y-C2.c.y)*(C1.c.y-C2.c.y));
//外离或外切
if(d >= C1.r+C2.r) { printf("0.000\n"); return 0; }
//内含或内切或重合
if(dcmp(max(C1.r, C2.r)-min(C1.r, C2.r)-d) >= 0) {
printf("%.3lf\n", min(C1.r, C2.r)*min(C1.r, C2.r)*PI);
return 0;
}
//相交
Vector v1, v2;
d = Length(p1-p2);
v1 = p1-C1.c, v2 = p2-C1.c;
double s11 = Area(Length(v1), Length(v2), Length(d)), s12 = C1.r*C1.r*Angle(v1, v2) / 2;
v1 = p1-C2.c, v2 = p2-C2.c;
double s21 = Area(Length(v1), Length(v2), Length(d)), s22 = C2.r*C2.r*Angle(v1, v2) / 2;
//讨论交点位置
if(dcmp(C1.c.x-p1.x) * dcmp(C2.c.x-p1.x) <= 0)
printf("%.3lf\n", s12+s22 - s11-s21);
else {
if(C1.r > C2.r) printf("%.3lf\n", C2.S() + s21 - s22 - s11 + s12);
else printf("%.3lf\n", C1.S() + s11 - s12 - s21 + s22); //WA
}
return 0;
}
更为简单的方法:
10ms,256 kB
#include<cstdio>
#include<cmath>
using namespace std;
int main() {
const double pi = acos(double(-1));
double x1, y1, r1, x2, y2, r2;
scanf("%lf%lf%lf%lf%lf%lf", &x1, &y1, &r1, &x2, &y2, &r2);
double z = hypot(x1-x2, y1-y2);
if(z >= r1 + r2) { printf("0.000"); return 0; }
if(r1 >= r2 + z) { printf("%.3lf\n", pi*r2*r2); return 0; }
double m = (r1*r1 - r2*r2 + z*z) / 2 / z;
double n = sqrt(r1*r1-m*m);
double o = r1*r1*pi*(asin(n/r1)/pi) - n*m;
double p = r2*r2*pi*(asin(n/r2)/pi) - n*fabs(z-m);
if(m > z) p = r2*r2*pi - p;
printf("%.3lf\n", o + p);
return 0;
}
原文地址:http://blog.csdn.net/qq_21110267/article/details/43614621