AcWing 3074. 自適應辛普森積分 3069. 圓的面積並[BZOJ2178]
阿新 • • 發佈:2021-02-15
技術標籤:計算幾何
模板題3074. 自適應辛普森積分
題意
思路
辛普森積分:(r - l) * (f(l) + f(mid) * 4 + f(r)) / 6.0 指過l,r,(l + r) / 2 三處確定點在拋物線上的積分的面積
自適應辛普森積分:每次找l~r與l~mid+mid~r比較fabs<eps說明已經精確可用(對二次函式次數更高就不好說了)過程就是遞迴
程式碼
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const double eps = 1e-12; double l,r; double dcmp(double x){ if(fabs(x) < eps) return 0; if(x > 0) return 1; return -1; } double f(double x){ return sin(x) / x; } double simpson(double l,double r){//辛普森積分公式 double mid = (l + r) / 2; return (r - l) * (f(l) + f(mid) * 4 + f(r)) / 6.0; } double asr(double l,double r,double S){ double mid = (l + r) / 2; double left = simpson(l,mid); double right = simpson(mid,r); if(dcmp(S - (left + right)) == 0) return left + right; return asr(l,mid,left) + asr(mid,r,right); } int main(){ scanf("%lf%lf",&l,&r); printf("%.6f\n",asr(l,r,simpson(l,r))); return 0; }
3069. 圓的面積並
題意
思路
將f(x)計算為橫座標=x時跨越的圓在縱座標方向上的長度
程式碼
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const double eps = 1e-8; const int MaxN = 1e3 + 5; int n; struct Point{ double x,y; }q[MaxN]; struct Circle{ Point C; double r; }c[MaxN]; int dcmp(double x){ if(fabs(x) < eps) return 0; if(x > 0) return 1; return -1; } bool cmp(Point A,Point B){ return A.x < B.x; } double f(double x){ int cnt = 0; double ans = 0; for(int i = 0;i < n; i++){ double R = c[i].r,dis = fabs(x - c[i].C.x); if(dcmp(R - dis) <= 0) continue; double h = sqrt(R * R - dis * dis); double Y1 = c[i].C.y - h; double Y2 = c[i].C.y + h; q[++cnt] = {Y1,Y2}; } if(cnt == 0) return 0; sort(q + 1,q + 1 + cnt,cmp); double lst = q[1].x,ed = q[1].y; for(int i = 2;i <= cnt; i++){ if(q[i].x <= ed) ed = max(ed,q[i].y); else{ ans += ed - lst; lst = q[i].x,ed = q[i].y; } } ans += ed - lst; return ans; } double simpson(double l,double r){ double mid = (l + r) / 2; return (r - l) * (f(l) + 4 * f(mid) + f(r)) / 6.0; } double asr(double l,double r,double S){ double mid = (l + r) / 2; double left = simpson(l,mid); double right = simpson(mid,r); if(!dcmp(S - left - right)) return left + right; return asr(l,mid,left) + asr(mid,r,right); } int main() { scanf("%d",&n); for(int i = 0;i < n; i++){ scanf("%lf %lf %lf",&c[i].C.x,&c[i].C.y,&c[i].r); } double l = -2000,r = 2000; printf("%.3f\n",asr(l,r,simpson(l,r))); return 0; }