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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值