SPOJ CIRU 圆的面积并 自适应辛普森积分

简略题意:给出n个圆,求他们的面积并。

  1. 去掉内含圆,因为不会对答案造成影响。
  2. 去掉和其他圆都相离的圆,这部分答案直接计算。
    这样我们就只用计算和别的圆相交的圆的面积了。
  3. 辛普森积分暴力搞吧,对于x = a的直线,看多少圆覆盖了这条直线,求出这部分的长度即可。
#define poj
#ifdef poj
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#endif // poj
#ifdef others
#include <bits/stdc++.h>
#endif // others
//#define file
#define all(x) x.begin(), x.end()
using namespace std;
const double pi = acos(-1.0);

typedef long long LL;
typedef unsigned long long ULL;
void umax(int &a, int b) {
    a = max(a, b);
}
void umin(int &a, int b) {
    a = min(a, b);
}

void file() {
    freopen("a.in", "r", stdin);
//    freopen("1.txt", "w", stdout);
}

namespace Solver {
    int n;
    struct point {
        double x, y;
    };
    struct cir {
        point o;
        double r;
        bool operator < (const cir & b) const {
            return r < b.r;
        }
    } c[1111];
    vector<cir> G, V;
    bool tag[1111];
    double dis(point a, point b) {
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
    }
    bool is_covered(cir a, cir b) {
        return dis(a.o, b.o) + a.r <= b.r;
    }
    bool is_apart(cir a, cir b) {
        return dis(a.o, b.o) > a.r + b.r;
    }
    struct Itv {
        double l, r;
        bool operator < (const Itv & x) const {
            return l < x.l || (l == x.l && r < x.r);
        }
    };
    double F(double x) {
        vector<Itv> R;
        double sum = 0;
        for(int i = 0; i < V.size(); i++) {
            if(x >= V[i].o.x - V[i].r && x <= V[i].o.x + V[i].r) {
                double len = sqrt(V[i].r*V[i].r-(V[i].o.x-x)*(V[i].o.x-x));
                R.push_back({V[i].o.y - len, V[i].o.y + len});
            }
        }
        sort(all(R));
        double pre = -1e20;
        for(int i = 0; i < R.size(); i++) {
            pre = max(pre, R[i].l);
            sum += max(0.0, R[i].r - pre);
            pre = max(pre, R[i].r);
        }
        return sum;
    }

    double simpson(double a, double b) {
        double c = a + (b - a) / 2;
        return (F(a) + 4 * F(c) + F(b))*(b - a) / 6;
    }

    double asr(double a, double b, double eps, double A) {
        double c = a + (b - a) / 2;
        double L = simpson(a, c), R = simpson(c, b);
        if (fabs(L + R - A) <= 15 * eps)return L + R + (L + R - A) / 15.0;
        return asr(a, c, eps / 2, L) + asr(c, b, eps / 2, R);
    }

    double asr(double a, double b, double eps) {
        return asr(a, b, eps, simpson(a, b));
    }
    void solve() {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++) {
            double x, y, r;
            scanf("%lf%lf%lf", &x, &y, &r);
            c[i] = {x, y, r};
        }
        sort(c + 1, c + 1 + n);
        for(int i = 1; i <= n; i++)
            for(int j = i + 1; j <= n; j++) {
                if(is_covered(c[i], c[j]))
                    tag[i] = 1;
            }
        double ans = 0;
        for(int i = 1; i <= n; i++)
            if(!tag[i]) G.push_back(c[i]);
        memset(tag, 0, sizeof tag);
        for(int i = 0; i < G.size(); i++) {
            int cnt = 0;
            for(int j = 0; j < G.size(); j++)
                cnt += is_apart(G[i], G[j]);
            if(cnt == G.size() - 1)
                ans += G[i].r*G[i].r*pi, tag[i] = 1;
        }
        for(int i = 0; i < G.size(); i++)
            if(tag[i] == 0) V.push_back(G[i]);
        printf("%.3f\n", asr(-2000, 2000, 1e-6) + ans);
    }
};

int main() {
//    file();
    Solver::solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值