多圆相交模板

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;

const double PI = acos(-1.0);
const double EPS = 1e-8;

double Deg2Rad(double deg){return (deg * PI / 180.0);}
double Rad2Deg(double rad){return (rad * 180.0 / PI);}
double Sin(double deg){return sin(Deg2Rad(deg));}
double Cos(double deg){return cos(Deg2Rad(deg));}
double ArcSin(double val){return Rad2Deg(asin(val));}
double ArcCos(double val){return Rad2Deg(acos(val));}
double Sqrt(double val){return sqrt(val);}

inline int sgn(double x) {
    return (x > EPS) - (x < -EPS);
}

inline double sqr(double x) {
    return x * x;
}

struct Point {
    double x, y;
    Point() {}
    Point(double x, double y): x(x), y(y) {}
    void read() {
        scanf("%lf%lf", &x, &y);
    }
    double length() const {
        return sqrt(x * x + y * y);
    }
    Point operator + (const Point &rhs) const {
        return Point(x + rhs.x, y + rhs.y);
    }
    Point operator - (const Point &rhs) const {
        return Point(x - rhs.x, y - rhs.y);
    }
    Point operator * (double t) const {
        return Point(x * t, y * t);
    }
    Point operator / (double t) const {
        return Point(x / t, y / t);
    }
    Point unit() const {
        double l = length();
        return *this / l;
    }
    double angle() const {
        return atan2(y, x);
    }
};

double dist(const Point &a, const Point &b) {
    return (a - b).length();
}

Point rotate(const Point &p, double angle, const Point &o = Point(0, 0)) {
    Point t = p - o;
    double x = t.x * cos(angle) - t.y * sin(angle);
    double y = t.y * cos(angle) + t.x * sin(angle);
    return Point(x, y) + o;
}

double cross(const Point &a, const Point &b) {
    return a.x * b.y - a.y * b.x;
}

double cross(const Point &sp, const Point &ep, const Point &op) {
    return cross(sp - op, ep - op);
}

struct Region {
    double st, ed;
    Region() {}
    Region(double st, double ed): st(st), ed(ed) {}
};

struct Circle {
    Point c;
    double r;
    Circle() {}
    Circle(Point c, double r): c(c), r(r) {}
    void read() {
        c.read();
        scanf("%lf", &r);
    }
    double area() const {
        return PI * r * r;
    }
    bool contain(const Circle &rhs) const {
        return sgn(dist(c, rhs.c) + rhs.r - r) <= 0;
    }
    bool contain(const Point &p) const {
        return sgn(dist(c, p) - r) <= 0;
    }
    bool intersect(const Circle &rhs) const {
        return sgn(dist(c, rhs.c) - r - rhs.r) < 0;
    }
    bool tangency(const Circle &rhs) const {
        return sgn(dist(c, rhs.c) - r - rhs.r) == 0;
    }
    Point pos(double angle) const {
        Point p = Point(c.x + r, c.y);
        return rotate(p, angle, c);
    }
};

void intersection(const Circle &cir1, const Circle &cir2, Point &p1, Point &p2) {
    double l = dist(cir1.c, cir2.c);
    double d = (sqr(l) - sqr(cir2.r) + sqr(cir1.r)) / (2 * l);
    double d2 = sqrt(sqr(cir1.r) - sqr(d));
    Point mid = cir1.c + (cir2.c - cir1.c).unit() * d;
    Point v = rotate(cir2.c - cir1.c, PI / 2).unit() * d2;
    p1 = mid + v, p2 = mid - v;
}

const int MAXN = 10;


struct Region_vector {
    int n;
    Region v[5];
    void clear() {
        n = 0;
    }
    void add(const Region &r) {
        v[n++] = r;
    }
} *last, *cur;

Circle cir[MAXN];
bool del[MAXN];
double r;
int n = 5;

double CommonArea(const Circle &A, const Circle &B) {
    double area = 0.0;
    const Circle & M = (A.r > B.r) ? A : B;
    const Circle & N = (A.r > B.r) ? B : A;
    double D = dist(M.c, N.c);
    if((D < M.r + N.r) && (D > M.r - N.r)) {
        double cosM = (M.r * M.r + D * D - N.r * N.r) / (2.0 * M.r * D);
        double cosN = (N.r * N.r + D * D - M.r * M.r) / (2.0 * N.r * D);
        double alpha = 2.0 * ArcCos(cosM);
        double beta = 2.0 * ArcCos(cosN);
        double TM = 0.5 * M.r * M.r * Sin(alpha);
        double TN = 0.5 * N.r * N.r * Sin(beta);
        double FM = (alpha / 360.0) * M.area();
        double FN = (beta / 360.0) * N.area();
        area = FM + FN - TM - TN;
    }
    else if(D <= M.r - N.r) {
        area = N.area();
    }
    return area;
}

bool isOnlyOnePoint() {
    bool flag = false;
    Point t;
    for(int i = 0; i < n; ++i)
        for(int j = i + 1; j < n; ++j) {
            if(cir[i].tangency(cir[j])) {
                flag = true;
                t = (cir[i].c + cir[j].c) / 2;
                break;
            }
        }
    if(!flag) return false;
    for(int i = 0; i < n; ++i)
        if(!cir[i].contain(t)) return false;
    printf("Only the point (%.2f, %.2f) is for victory.\n", t.x + EPS, t.y + EPS);
    return true;
}

bool solve() {
    if(isOnlyOnePoint()) return true;
    memset(del, 0, sizeof(del));
    for(int i = 0; i < n; ++i)
        for(int j = 0; j < n; ++j) {
            if(del[j] || i == j) continue;
            if(cir[i].contain(cir[j])) {
                del[i] = true;
                break;
            }
        }
    double ans = 0;
    for(int i = 0; i < n; ++i) {
        if(del[i]) continue;
        last->clear();
        Point p1, p2;
        for(int j = 0; j < n; ++j) {
            if(del[j] || i == j) continue;
            if(!cir[i].intersect(cir[j])) return false;
            cur->clear();
            intersection(cir[i], cir[j], p1, p2);
            double rs = (p2 - cir[i].c).angle(), rt = (p1 - cir[i].c).angle();
            if(sgn(rs) < 0) rs += 2 * PI;
            if(sgn(rt) < 0) rt += 2 * PI;
            if(last->n == 0) {
                if(sgn(rt - rs) < 0) cur->add(Region(rs, 2 * PI)), cur->add(Region(0, rt));
                else cur->add(Region(rs, rt));
            } else {
                for(int k = 0; k < last->n; ++k) {
                    if(sgn(rt - rs) < 0) {
                        if(sgn(last->v[k].st - rt) >= 0 && sgn(rs - last->v[k].ed) >= 0) continue;
                        if(sgn(last->v[k].st - rt) < 0) cur->add(Region(last->v[k].st, min(last->v[k].ed, rt)));
                        if(sgn(rs - last->v[k].ed) < 0) cur->add(Region(max(last->v[k].st, rs), last->v[k].ed));
                    } else {
                        if(sgn(rt - last->v[k].st) <= 0 || sgn(last->v[k].ed - rs) <= 0) continue;
                        cur->add(Region(max(rs, last->v[k].st), min(rt, last->v[k].ed)));
                    }
                }
            }
            swap(last, cur);
            if(last->n == 0) break;
        }
        for(int j = 0; j < last->n; ++j) {
            p1 = cir[i].pos(last->v[j].st);
            p2 = cir[i].pos(last->v[j].ed);
            ans += cross(p1, p2) / 2;
            double angle = last->v[j].ed - last->v[j].st;
            ans += 0.5 * sqr(cir[i].r) * (angle - sin(angle));
        }
    }
    if(sgn(ans) == 0) return false;
    printf("The total possible area is %.2f.\n", ans + EPS);
    //printf("%.2f\n", CommonArea(cir[0], cir[4]));
    return true;
}

int main() {
    last = new Region_vector, cur = new Region_vector;
    while(scanf("%lf", &r) != EOF) {
        Point t;
        for(int i = 0; i < n; ++i) {
            t.read();
            cir[i] = Circle(t, r);
        }
        if(!solve()) puts("Poor iSea, maybe 2012 is coming!");
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值