三天前想学一因为各种各样的事情耽误... 昨天从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);
}