【学习笔记】自适应辛普森法(ASR)
前言
蒟蒻的计算几何简直太垃圾了,什么都不会,所以要从最简单的东西开始......要是出现错误,请在下方评论区指出。
为了让某一天 或者每天 犯傻的 sb 显然的语言解释,巨佬们不要嫌我啰嗦
正题
如果我们需要求解这样一个东西:
我们显然有两种方法:
1、直接极限搞,把这段区间分割为无数个小区间,就有:
2、牛顿-莱布尼茨公式法,令
这两种方法都有一定的适应范围,但对于一些两种方法都不适用的呢,我们就需要自适应辛普森法......
辛普森公式
辛普森公式其实思路很简单,对于一些我们不是很好积分的函数,直接拿跟这个函数差不多的二次函数近似它,然后去积二次函数
假设
那我们有这样一个东西:
我们就得出了这个公式:
代码大概长这样:
inline double simpson(double l,double r) {
double mid = (l + r) / 2;
return (f(l) + 4 * f(mid) + f(r)) * (r - l) / 6;
}
显然这东西误差很大,如果是一个长得不那么二次函数的函数,那就得凉凉,但是可以发现 感性理解
那么我们现在就需要处理精度问题了
自适应辛普森法(ASR)
大概思路就是把
但是分少了精度不够,分多了
我们设
首先我们对于区间
那么如果
其实我也不知道为什么是15倍的eps
否则,分左右两边递归,把答案相加返回即可
代码长这样:
double asr(double l,double r,double eps,double ans) {
double mid = (l + r) / 2;
double Lv = simpson(l,mid),Rv = simpson(mid,r);
if(fabs(Lv + Rv - ans) <= 15 * eps) return Lv + Rv + (Lv + Rv - ans) / 15;
return asr(l,mid,eps / 2,Lv) + asr(mid,r,eps / 2,Rv);
}
需要注意的是,区间缩小为之前的一半之后,
然后就做完了
板子 P4525 【模板】自适应辛普森法1
直接上板子即可,没有任何区别
#include<bits/stdc++.h>
using namespace std;
double a,b,c,d,L,R;
inline double f(double x) {return (c * x + d) / (a * x + b);}
inline double simpson(double l,double r) {
double mid = (l + r) / 2;
return (f(l) + 4 * f(mid) + f(r)) * (r - l) / 6;
}
double asr(double l,double r,double eps,double ans) {
double mid = (l + r) / 2;
double Lv = simpson(l,mid),Rv = simpson(mid,r);
if(fabs(Lv + Rv - ans) <= 15 * eps) return Lv + Rv + (Lv + Rv - ans) / 15;
return asr(l,mid,eps / 2,Lv) + asr(mid,r,eps / 2,Rv);
}
inline double ASR(double l,double r,double eps) {return asr(l,r,eps,simpson(l,r));}
int main () {
scanf("%lf%lf%lf%lf%lf%lf",&a,&b,&c,&d,&L,&R);
printf("%.6lf\n",ASR(L,R,1e-6));
return 0;
}
板子 P4526 【模板】自适应辛普森法2
这个稍微有一点点地方需要想想
它要我们求
如果积分发散,输出
显然当
然后我们把这个函数丢到画图软件里面很快可以发现:
同时我们可以发现,当
以上证明待补
它让我们保留
保险起见,我的右端设的是
#include<bits/stdc++.h>
using namespace std;
double a;
inline double f(double x) {return pow(x,(a / x) - x);}
inline double simpson(double l,double r) {
double mid = (l + r) / 2;
return (f(l) + 4 * f(mid) + f(r)) * (r - l) / 6;
}
double asr(double l,double r,double eps,double ans) {
double mid = (l + r) / 2;
double Lv = simpson(l,mid),Rv = simpson(mid,r);
if(fabs(Lv + Rv - ans) <= 15 * eps) return Lv + Rv + (Lv + Rv - ans) / 15;
return asr(l,mid,eps / 2,Lv) + asr(mid,r,eps / 2,Rv);
}
inline double ASR(double l,double r,double eps) {return asr(l,r,eps,simpson(l,r));}
int main () {
scanf("%lf",&a);
if(a < 0) return puts("orz"),0;
printf("%.5lf\n",ASR(1e-8,12,1e-8));
return 0;
}
例题
咕咕咕
时间复杂度多少啊?
貌似是 O玄 学 ,这个东西好像还比较好卡
大爱cxy07