自适应Simpson积分

一般用于在坐标系上求面积。
公式是\( S=\frac{f(l)+4*f(mid)+f(r)}{6} \),其中f为对应x的y值。也就是用二次函数拟合。
至于为什么是自适应:因为使用二次函数拟合,所以对于一段x区间[a,b],考虑对[a,b]求S,再求[a,(a+b)/2]和[(a+b)/2,b]的S和。然后看这两部分的差是否在eps内,是的话则返回答案,否则递归求解[a,(a+b)/2]和[(a+b)/2,b]。这样一来,对于比较波折的段,会递归到较为精确的[a,b],对于较平滑的段则会去少数点。
例题:
hdu 1071
题意:求椭圆面积
直接板子,注意结果*2

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const double eps=1e-9;
int T;
double a,b,l,r;
int cmp(double x)
{
	if(x<=eps&&x>=-eps)
		return 0;
	return x>0?1:-1;
}
double f(double x)
{
	return b*sqrt(1.0-x*x/(a*a));
}
double sps(double l,double r,double now,double fl,double fr,double fm)
{
	double mid=(l+r)/2,ffl=f((l+mid)/2),ffr=f((mid+r)/2),p=(fl+fm+ffl*4)*(mid-l)/6,q=(fm+fr+ffr*4)*(r-mid)/6;
	if(cmp(now-p-q)==0)
		return now;
	else
		return sps(l,mid,p,fl,fm,ffl)+sps(mid,r,q,fm,fr,ffr);
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		scanf("%lf%lf%lf%lf",&a,&b,&l,&r);
		double fl=f(l),fr=f(r),fm=f((l+r)/2);
		printf("%.3lf\n",2*sps(l,r,(fl+4*fm+fr)*(r-l)/6,fl,fr,fm));
	}
	return 0;
}

bzoj 2178 https://www.cnblogs.com/lokiii/p/8452281.html
bzoj 1502 https://www.cnblogs.com/lokiii/p/8452291.html

posted @ 2018-02-17 22:29  lokiii  阅读(263)  评论(0编辑  收藏  举报