bjfu1235 两圆公共面积

给定两个圆,求其覆盖的面积,其实也就是求其公共面积(然后用两圆面积和减去此值即得最后结果)。

我一开始是用计算几何的方法做的,结果始终不过。代码如下:

/*
 * Author    : ben
 */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <functional>
#include <numeric>
#include <cctype>
using namespace std;
const double pi = acos(-1);
typedef struct MyPoint {
    double x, y;
    MyPoint(double xx = 0, double yy = 0) {
        x = xx;
        y = yy;
    }
} MyPoint;

inline double mydistance2(const MyPoint &p1, const MyPoint &p2) {
    return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}

inline double mydistance(const MyPoint &p1, const MyPoint &p2) {
    return sqrt(mydistance2(p1, p2));
}

MyPoint intersection(MyPoint u1, MyPoint u2, MyPoint v1, MyPoint v2) {
    MyPoint ret = u1;
    double t = ((u1.x - v1.x) * (v1.y - v2.y) - (u1.y - v1.y) * (v1.x - v2.x))
            / ((u1.x - u2.x) * (v1.y - v2.y) - (u1.y - u2.y) * (v1.x - v2.x));
    ret.x += (u2.x - u1.x) * t;
    ret.y += (u2.y - u1.y) * t;
    return ret;
}

void intersection_line_circle(MyPoint c, double r, MyPoint l1, MyPoint l2,
        MyPoint& p1, MyPoint& p2) {
    MyPoint p = c;
    double t;
    p.x += l1.y - l2.y;
    p.y += l2.x - l1.x;
    p = intersection(p, c, l1, l2);
    t = sqrt(r * r - mydistance(p, c) * mydistance(p, c)) / mydistance(l1, l2);
    p1.x = p.x + (l2.x - l1.x) * t;
    p1.y = p.y + (l2.y - l1.y) * t;
    p2.x = p.x - (l2.x - l1.x) * t;
    p2.y = p.y - (l2.y - l1.y) * t;
}

void intersection_circle_circle(MyPoint c1, double r1, MyPoint c2, double r2,
        MyPoint& p1, MyPoint& p2) {
    MyPoint u, v;
    double t;
    t = (1 + (r1 * r1 - r2 * r2) / mydistance(c1, c2) / mydistance(c1, c2)) / 2;
    u.x = c1.x + (c2.x - c1.x) * t;
    u.y = c1.y + (c2.y - c1.y) * t;
    v.x = u.x + c1.y - c2.y;
    v.y = u.y - c1.x + c2.x;
    intersection_line_circle(c1, r1, u, v, p1, p2);
}

int main() {
    freopen("data.in", "r", stdin);
//    freopen("data.out", "w", stdout);
    int T;
    double x, y, r1, r2;
    scanf("%d", &T);
    double ans;
    while (T--) {
        scanf("%lf%lf%lf", &x, &y, &r1);
        MyPoint c1(x, y);
        scanf("%lf%lf%lf", &x, &y, &r2);
        MyPoint c2(x, y);
        double dis2 = mydistance2(c1, c2);
        double dis = sqrt(dis2);
        if (dis >= r1 + r2) { //相离
            ans = pi * r1 * r1 + pi * r2 * r2;
        } else if (dis <= fabs(r1 - r2)) { //包含
            double r = r1 > r2 ? r1 : r2;
            ans = pi * r * r;
        } else { //相交
            MyPoint p1, p2;
            intersection_circle_circle(c1, r1, c2, r2, p1, p2);
            double d2 = mydistance(p1, p2) / 2;
            double angle1 = asin(d2 / r1);
            double angle2 = asin(d2 / r2);
            double Sanjiao1 = sqrt(r1 * r1 - d2 * d2) * d2;
            double Sanjiao2 = sqrt(r2 * r2 - d2 * d2) * d2;
            double San1 = r1 * r1 * angle1;
            double San2 = r2 * r2 * angle2;
            ans = pi * r1 * r1 + pi * r2 * r2;
            ans -= San1 + San2 - Sanjiao1 - Sanjiao2;
        }
        printf("%.6f\n", ans);
    }
    return 0;
}

根据后来的调试,应该是对如下图b的情况处理不正确。

于是后来上网找了几个中学的解析几何公式,终于a了。

做法是联立两个圆的方程(相减),得到相交弦所在直线方程,然后用点到直接的距离公式得到h1和h2,接着算出θ1和θ2,然后就能求得三角形的面积和扇形的面积了。一开始我以为需要分类讨论上面图a和图b两种情况,后来发现,直接去掉求距离时的取绝对值运算就可以了,因为距离为负的时候,得到的夹角也是负的,这样求的三角形面积是负的,扇形也是原先的相补的那部分,具体的图我就不画了,很容易想明白的。

AC代码如下:

/*
 * Author    : ben
 */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <vector>
#include <deque>
#include <list>
#include <functional>
#include <numeric>
#include <cctype>
using namespace std;
const double pi = acos(-1);
typedef struct MyPoint {
    double x, y;
    MyPoint(double xx = 0, double yy = 0) {
        x = xx;
        y = yy;
    }
} MyPoint;

inline double mydistance2(const MyPoint &p1, const MyPoint &p2) {
    return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}

int main() {
//    freopen("data.in", "r", stdin);
    int T;
    scanf("%d", &T);
    double ans, r1, r2;
    MyPoint c1, c2;
    while (T--) {
        scanf("%lf%lf%lf", &c1.x, &c1.y, &r1);
        scanf("%lf%lf%lf", &c2.x, &c2.y, &r2);
        double dis2 = mydistance2(c1, c2);
        double dis = sqrt(dis2);
        if (dis >= r1 + r2) { //相离
            ans = pi * r1 * r1 + pi * r2 * r2;
        } else if (dis <= fabs(r1 - r2)) { //包含
            double r = r1 > r2 ? r1 : r2;
            ans = pi * r * r;
        } else { //相交
            //h1和h2可能为负
            double h1 = (dis2 + r1 * r1 - r2 * r2) / dis / 2.0;
            double h2 = dis - h1;
            double angle1 = acos(h1 / r1);
            double angle2 = acos(h2 / r2);
            double Sanjiao = sqrt(r1 * r1 - h1 * h1) * dis;
            double Sanxin1 = r1 * r1 * angle1;
            double Sanxin2 = r2 * r2 * angle2;
            ans = pi * r1 * r1 + pi * r2 * r2;
            ans -= Sanxin1 + Sanxin2 - Sanjiao;
        }
        printf("%.6f\n", ans);
    }
    return 0;
}
时间: 2024-10-29 19:10:00

bjfu1235 两圆公共面积的相关文章

poj 2546(两圆公共面积)

Circular Area Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5682   Accepted: 2225 Description Your task is to write a program, which, given two circles, calculates the area of their intersection with the accuracy of three digits after

POJ 2546 &amp; ZOJ 1597 Circular Area 两圆的面积交

Circular Area Time Limit: 2 Seconds      Memory Limit: 65536 KB Your task is to write a program, which, given two circles, calculates the area of their intersection with the accuracy of three digits after decimal point. Input In the single line of in

HDU 1798 两圆相交面积

Tell me the area Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 1755    Accepted Submission(s): 535 Problem Description There are two circles in the plane (shown in the below picture), there is

poj2546Circular Area(两圆相交面积)

链接 画图推公式 这两种情况 都可用一种公式算出来 就是两圆都求出圆心角 求出扇形的面积减掉三角形面积 #include <iostream> using namespace std; #include<cmath> #include<iomanip> #include<algorithm> int main() { double d,t,t1,s,x,y,xx,yy,r,rr; while(cin>>x>>y>>r) {

[hdu 3264] Open-air shopping malls(二分+两圆相交面积)

题目大意是:先给你一些圆,你可以任选这些圆中的一个圆点作圆,这个圆的要求是:你画完以后.这个圆要可以覆盖之前给出的每一个圆一半以上的面积,即覆盖1/2以上每一个圆的面积. 比如例子数据,选左边还是选右边没差别,红色的圆为答案(选了左边的圆点),它覆盖了左边圆的1/2以上,也覆盖了右边圆的1/2以上. 知道了怎样求两圆面积交.那么这道题就简单了.仅仅要二分答案,然后枚举每个圆点,假设全都覆盖了1/2以上就继续二分,最后答案就得出来了. #include<iostream> #include<

poj 2546 Circular Area (两圆相交面积)

链接:poj 2546 题意:已知两圆的圆心和半径,求两圆相交部分的面积 分析:两圆的位置关系有三种:相离,相交,内含 相离时:相交面积为0 相交时,大扇形面积+小扇形面积-四边形面积 内含时,相交面积为小圆面积 #include<stdio.h> #include<math.h> #define PI acos(-1.0) typedef struct stu { double x,y; }point; double Distance(point a,point b) { ret

URAL 1825. Ifrit Bomber 2 两圆的面积并

1825. Ifrit Bomber 2 Time limit: 0.5 second Memory limit: 64 MB The very first use of ifrit bottles caused mass protests from the world community. The UNESCO declared that ifrit bombardments were destroying the historical centers of large cities, whi

求两圆相交面积模板

#define PI 3.141592654 #define eps 1e-8 double getdis(int x1,int y1,int x2,int y2){ return sqrt((double)(x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); } double getarea(int x1,int y1,double r1,int x2,int y2,double r2){ double d=getdis(x1,y1,x2,y2); if(r1+r2<d+eps)

POJ 2546 &amp; ZOJ 1597 Circular Area(求两圆相交的面积 模板)

题目链接: POJ:http://poj.org/problem?id=2546 ZOJ:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=597 Description Your task is to write a program, which, given two circles, calculates the area of their intersection with the accuracy of three di