題解
需要考慮幾種情況:
外切或外離。面積為0,注意要輸出 0.000。內切或內含或重合。面積為較小圓的面積。相交,還需要討論交點位置:
在求三角形面積的時候有兩種方法:
運用三角形兩邊的叉積的絕對值的1/2計算。運用海倫公式計算。
不過我試了所有方法仍然有一個點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); }
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 d = hypot(x1-x2, y1-y2);
if(d >= r1 + r2) {
printf(
"0.000");
return 0; }
if(r1 >= r2 + d) {
printf(
"%.3lf\n", pi*r2*r2);
return 0; }
double m = (r1*r1 - r2*r2 + d*d) /
2 / d;
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(d-m);
if(m > d) p = r2*r2*pi - p;
printf(
"%.3lf\n", o + p);
return 0;
}
總結
以上是生活随笔為你收集整理的[codevs 3273] 两圆的交的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。