自适应辛普森法
例题
洛谷P4526 【模板】自适应辛普森法2
这道题应该不能用牛顿莱布尼兹公式求解,因为这个函数没有初等原函数。(P4525还是算了吧,可以直接查积分表,不过要注意分类讨论)
近似值求法——辛普森法(也叫抛物线法)
辛普森法将定积分范围划分成n个小段,每一段都当做一段抛物线(二次函数)分别求定积分,最后累加起来。
∫ a b f ( x ) d x ≈ b − a 3 n [ ( y 0 + y n ) + 2 ∑ i = 2 n − 2 y i + 4 ∑ i = 1 n − 1 y i ] \int_{a}^{b}f(x)dx \approx \frac{b-a}{3n}[(y_{0}+y_{n})+2\sum_{i=2}^{n-2}y_{i}+4\sum_{i=1}^{n-1}y_{i}] ∫abf(x)dx≈3nb−a[(y0+yn)+2i=2∑n−2yi+4i=1∑n−1yi]
#include <bits/stdc++.h>
using namespace std;
double a;
const double INF = 100;
const int n = 1000;
double f(double x)
{
return pow(x,a/x-x);
}
double Simpson()
{
double s1 = 0,s2 = 0;
double h=INF/n;
for(int k = 1;k <= n-1;k++)
{
s1+=f(k*h+h/2);
s2+=f(k*h);
}
s1+=f(INF+h/2);
return h/6*(4*s1+2*s2+f(INF));
}
int main()
{
scanf("%lf",&a);
printf("%0.5lf",Simpson());
return 0;
}
这样可以得80分。
优化——自适应辛普森法
自适应辛普森法是每次将区间对折为两个,若将整个区间当做抛物线求得的定积分与左右区间分别当做抛物线求得的定积分之和误差不超过最小精度,则返回,否则递归下去。
#include <bits/stdc++.h>
using namespace std;
double a;
double f(double x)
{
return pow(x,a/x-x);
}
double Simpson(double l,double r)
{
return (r-l)/6.0*(f(l)+f(r)+4.0*f((l+r)/2.0));
}
double Adaptive(double l,double r,double esp,double ans)
{
double mid=(l+r)/2.0,lans=Simpson(l,mid),rans=Simpson(mid,r);
if(fabs(lans+rans-ans)<=esp) return ans;
else return Adaptive(l,mid,esp,lans)+Adaptive(mid,r,esp,rans);
}
int main()
{
scanf("%lf",&a);
if(a<0) printf("orz");
else printf("%0.5lf",Adaptive(1e-12,20,1e-12,Simpson(1e-12,10)));
return 0;
}
这样就可以得100分了。