[BZOJ]2178 圆的面积并 Simpson积分

本文探讨了使用Simpson积分法解决一个特定问题:计算线段穿过圆时形成的长度。通过与传统几何方法的对比,讨论了Simpson积分法的应用及其优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  三天前想学一因为各种各样的事情耽误... 昨天从wys那里学到. 发现这个就是公式 +暴力? 公式要用导数来推, 但是只适用于二次函数...

  但是Simpson积分的自适应就在于用simpson算当前的now,左边的p和右边的q,如果加起来!=now那就继续递归算... 但是想想这样很容易被卡wa啊... 而且时间复杂度也大... 比如说这道题算函数值就是线段穿过圆的长度, 算一次很麻烦... 于是又问了wys正解是什么, 大概聊天过程如下.

  wys:"我们考虑正常人一般计算怎么算——"

  zyc: "正常人一般怎么算?? 正常人一般不会算啊!"(还没算过圆的面积并这种鬼畜玩意

  wys:"谁跟你说正常人不会算了!!!"

  zyc: "你会算吗?"

  wys:"不会."

  后来大概就是说算交点然后就是不断化成梯形加两个弓形面积.... 我选择Simpson.

#include<bits/stdc++.h>
#define xx first
#define yy second
using namespace std;
const double eps = 1e-13;
const int maxn = 1e3 + 5;
int n, m;
bool flag[maxn];
double lf = 1e5, rg = -1e5;
pair<double, double> b[maxn];
int sign(const double &x) {
    return (x > -eps) - (x < eps);
}
struct Circle {
    double x, y, r;
    inline friend bool operator < (const Circle &r, const Circle &s) {
        return r.r > s.r;
    }
    inline friend double operator * (const Circle &r, const Circle &s) {
        return (r.x - s.x) * (r.x - s.x) + (r.y - s.y) * (r.y - s.y);
    }
}a[maxn];
inline double F(const double &x) {
    int cnt = 0;
    double dist, len;
    for (int i = 1; i <= n; ++ i) {
        dist = fabs(a[i].x - x);
        if (sign(dist - a[i].r) < 0) {
            len = sqrt(a[i].r * a[i].r - dist * dist);
            b[++ cnt].xx = a[i].y - len, b[cnt].yy = a[i].y + len;
        }
    }
    if (!cnt) return 0;
    sort(b + 1, b + cnt + 1);
    double l = b[1].xx, r = b[1].yy, tmp = 0;
    for (int i = 2; i <= cnt; ++ i)
        if (sign(b[i].xx - r) <= 0)  r = max(r, b[i].yy);
        else tmp += r - l, l = b[i].xx, r = b[i].yy;
    tmp += r - l;
    return tmp;
}
double simpson(double l,double r,double now,double fl,double fr,double fmid) {
    double mid = (l + r) / 2, flmid = F((l + mid) / 2), frmid = F((mid + r) / 2);
    double p = (fl + fmid + flmid * 4) * (mid - l) / 6, q = (fmid + fr + frmid * 4) * (r - mid) / 6;
    if (!sign(now - p - q)) return p + q;
    else return simpson(l, mid, p, fl, fmid, flmid) + simpson(mid, r, q, fmid, fr, frmid);
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++ i) {
        scanf("%lf%lf%lf",&a[i].x, &a[i].y, &a[i].r);
        lf = min(lf, a[i].x - a[i].r);
        rg = max(rg, a[i].x + a[i].r);
    }
    sort(a + 1, a + n + 1);
    for (int i = 1; i <= n; ++ i)
        if (!flag[i])
            for (int j = i + 1; j <= n; ++ j)
                if (sign(sqrt(a[i] * a[j] + a[j].r - a[i].r )) <= 0) flag[j] = true;
    for (int i = 1; i <= n; ++ i)
        if (!flag[i]) a[++ m] = a[i];
    n = m;
    double fl = F(lf), fr = F(rg), fmid = F((lf + rg) / 2), ans;
    ans = simpson(lf, rg, (fl + fr + fmid * 4) * (rg - lf) / 6, fl, fr, fmid);
    printf("%.3lf\n", ans);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值