jzoj6678 苏菲的世界 (辛普森积分,圆与圆并)

编程入门 行业动态 更新时间:2024-10-05 07:29:01

jzoj6678 苏菲的世界 (辛普森<a href=https://www.elefans.com/category/jswz/34/1768675.html style=积分,圆与圆并)"/>

jzoj6678 苏菲的世界 (辛普森积分,圆与圆并)

题意

20个球,求面积并

做法

辛普森积分+圆并。
辛普森积分:知道一个函数在 l , r , 0.5 ( l + r ) l,r,0.5(l+r) l,r,0.5(l+r)处的值,可以估计其区间积分为 ( r − l ) ( f ( l ) + f ( r ) + 4 f ( 0.5 ( l + r ) ) ) 6 (r-l)\frac {(f(l)+f(r)+4f(0.5(l+r)))} 6 (r−l)6(f(l)+f(r)+4f(0.5(l+r)))​。二分处理,直到 r − l < = g a p r-l<=gap r−l<=gap且当前区间的估计值与子区间的估计值之差小于eps为止。
圆并做法:先去重合,去包含,然后考虑上轮廓减下轮廓,枚举每一个圆,用一些几何求出所有被覆盖的区间,然后再对没有被覆盖的区间做积分。

#include <bits/stdc++.h>
using namespace std;
typedef double db;
const db gap = 0.1, pi = acos(-1), eps = 1e-6;
const int N = 30;
int n, x[N], y[N], z[N], r[N];
struct pot{db x,y;pot(db _x=0, db _y=0) {x=_x,y=_y;}pot operator-(pot b){return pot(x-b.x,y-b.y);}pot operator+(pot b){return pot(x+b.x,y+b.y);}db operator*(pot b){return x*b.y-y*b.x;}pot operator*(db r){return pot(x*r,y*r);}
} o[N];
db R[N];
int m, del[N];
#define sqr(x) ((x)*(x))
#define zero(x) (abs(x)<=eps)
db len2(pot a) {return sqr(a.x)+sqr(a.y);
}pair<db,int> tp[N * 2];
int cc = 0;
void addseg(db l, db r) {tp[++cc]=make_pair(l,1);tp[++cc]=make_pair(r,-1);
}db ciruni() {db ret = 0;for(int i = 1; i <= m; i++) {cc = 0;tp[++cc]=make_pair(0,0);tp[++cc]=make_pair(-pi,0);tp[++cc]=make_pair(pi,0);for(int j = 1; j <= m; j++) if (i != j) {db d2 = len2(o[i] - o[j]);db d = sqrt(d2);if (d >= R[i] + R[j]) continue;db cs = (sqr(R[i]) + d2 - sqr(R[j])) * 0.5 / (R[i] * d);db ang = acos(cs);db b = atan2(o[j].y - o[i].y, o[j].x - o[i].x);db l = b - ang, r = b + ang;if (-pi <= l && r <= pi)addseg(l,r);else if (r > pi) {addseg(l,pi), addseg(-pi,r-2*pi);} else if (l < -pi) {addseg(-pi,r),addseg(l+2*pi,pi);}}sort(tp+1,tp+1+cc);int js=0;for(int j=1;j<cc;j++){js += tp[j].second;if(!zero(tp[j].first - tp[j + 1].first) && js == 0) {db jl = tp[j].first, jr = tp[j + 1].first;pot l = o[i] + pot(cos(jl), sin(jl)) * R[i];pot r = o[i] + pot(cos(jr), sin(jr)) * R[i];db w = jr - jl;ret -= (l.y + r.y) * 0.5 * (r.x - l.x);ret += w * R[i] * R[i] * 0.5 - R[i] * R[i] * sin(w) * 0.5;}}}return ret;
}db calc_z(db tz) {m=0;db xmx=-1000,xmi=1000;for(int i = 1; i <= n; i++) {if (z[i] - r[i] <= tz && tz <= z[i] + r[i]) {++m;o[m]=pot(x[i],y[i]);R[m]=sqrt(r[i]*r[i]-sqr(tz-z[i]));xmx=max(xmx,x[i]+R[m]);xmi=min(xmi,x[i]-R[m]);}}if (m==0)return 0;if (m==1)return pi*R[1]*R[1];memset(del,0,sizeof del);for(int i = 1; i <= m; i++) {for(int j = i + 1; j <= m; j++) {if (zero(o[i].x-o[j].x) && zero(o[i].y-o[j].y) && zero(R[i]-R[j])) {del[j] = 1;}}}for(int i=1;i<=m;i++){for(int j=1;j<=m;j++)if(j!=i&&R[i]>R[j]){if (len2(o[i]-o[j])<=sqr(R[i]-R[j]))del[j]=1;}}int tm=0;for(int i=1;i<=m;i++)if(!del[i]){o[++tm]=o[i];R[tm]=R[i];}m=tm;db v = ciruni();
//	printf("%.5lf %.5lf\n",tz,v);return v;
}db simp_z(db l, db r, db fl, db fr, db &fmid) {return (r-l)/6*(fl+fr+4*(fmid=calc_z((l+r)*0.5)));
}db sum_z(db lz, db rz, db s, db fl, db fr, db fmid) {db mid = 0.5 * (lz + rz), lmid = 0, rmid = 0;db ansl = simp_z(lz, mid, fl, fmid, lmid);db ansr = simp_z(mid, rz, fmid, fr, rmid);if (rz - lz > gap || abs(ansl + ansr - s) >= eps) {return sum_z(lz, mid, ansl, fl, fmid, lmid) + sum_z(mid, rz, ansr, fmid, fr, rmid);} else return ansl + ansr;
}db start_z(db lz, db rz) {db fl = calc_z(lz), fr = calc_z(rz), fmid = 0, z = simp_z(lz, rz, fl, fr, fmid);return sum_z(lz, rz, z, fl, fr, fmid);
}int main() {freopen("sphere.in","r",stdin);freopen("sphere.out","w",stdout);cin >> n;int zmx=-1000,zmi=1000;for(int i=1;i<=n;i++){scanf("%d %d %d %d",&x[i],&y[i],&z[i],&r[i]);zmx=max(zmx,z[i]+r[i]);zmi=min(zmi,z[i]-r[i]);}db ans = start_z(zmi, zmx);printf("%.3lf\n",ans);
}

更多推荐

jzoj6678 苏菲的世界 (辛普森积分,圆与圆并)

本文发布于:2024-02-13 11:02:44,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1758388.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:积分   辛普森   世界   苏菲

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!