1. 程式人生 > 其它 >AcWing 3074. 自適應辛普森積分 3069. 圓的面積並[BZOJ2178]

AcWing 3074. 自適應辛普森積分 3069. 圓的面積並[BZOJ2178]

技術標籤:計算幾何

模板題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;
}