自适应辛普森了解一下

A 了这道超短的紫题,来发表一下自己的一些想法...

简单介绍辛普森这玩意儿

不如先学学泰勒展开?

首先泰勒展开大家都听说过吧?【雾

没听说过?安利某知乎回答:苍老师教你如何更好地记忆泰勒展开

然后你就知道了,泰勒展开其实是对于某个函数在一个点不断去高阶求导,然后用求导得到的信息构造一个多项式,使得这个多项式在一定范围内几乎和原函数拟合(可以理解为接近重合的意思吧...)

类比到辛普森?

那么其实自适应辛普森也是类似的道理,只不过它是用了分治的方法去构造这个 拟合 多项式(其实就是二次函数,究其原因应该就是这玩意儿比较好积分并且存在弧度,容易拟合吧...)

自适应是个什么鬼?

至于为什么前面加了个自适应呢?因为我们考虑分治是要有终止条件的(像对于一个序列分治的话就是分治的区间长度为 1 时停止),但是我们这里是在实数域上拟合一个多项式啊,不存在什么规定的终止点...

于是我们考虑怎样去设置终止条件?那当然是给定一个误差范围(比如 1e-6),然后如果拟合函数和原函数大多数点的 y 值误差不超过这个范围就终止分治,直接拿当前的函数去积分就好了,当然具体怎么比较的先别管(你看到下面之后会发现根本不需要比较两个函数 2333 )

然后我们发现这个误差越大答案越不准确,越小跑的越慢,那么我们就要调整这个误差范围,然后这样的过程就有点像"自适应"了

拟合函数怎么构造?

我们先将原函数约等于成一个二次多项式:

\[f(x)≈Ax^2+Bx+C\]

然后题目要我们求的东西也转化一下:

\[ANS=\int_a^b f(x)dx\]

\[≈\int_a^b Ax^2+Bx+C\]

\[={A\over 3}(b^3-a^3) + {B\over 2} (b^2-a^2) +C(b-a)\]

\[={(b-a)\over 6} [ 2A(b^2+ab+a^2) + 3B(b+a)+6C]\]

\[={(b-a)\over 6} [ (Aa^2 + Ba+C) + (Ab^2+Bb+C)+4(~A~({a+b\over 2})^2 + B ({a+b\over2})+C)]\]

\[≈{(b-a)\over 6} [~ f(a) + f(b) + 4~f({a+b\over2})~]\]

恩?你问我推导哪里来的? 大佬%%%

我们发现最后约回去了,A B C 都不见了,而且这时候式子里面已经没有积分了...

所以怎么构造 A、B、C 还是没讲?

没错,我们发现上面其实根本不需要用到这个拟合二次函数的具体系数 A、B、C ,只需要将 f 的式子带入计算求值就好了

但是这样的话我们发现之前说的终止条件不见了,因为我们的拟合函数已经不需要了(而且找出来也很麻烦...)

其实我们只需要比较当前区间 \([a,b]\) 不分治时候的答案 \(ans\) 和 分治下的答案 \(ansL+ansR\) 的误差是否超过了我们设置的精度范围就好了

至于正确性?(我怎么知道)

因为我们知道这个分治肯定是层数越多越精确的,所以分治的结果精确度肯定高于当前 ans 的精确度,那么我们卡卡精度就能让答案在误差允许范围内了

FAQ: mmp 原来真的不用比较原函数和拟合函数...

如果要比较的话又能怎么比较呢?反正我是不会的...

code

代码超级短!相应的我们可以知道这里我们只需要将 f 函数改一改就能解决其他函数的积分问题了(一定精度下)

//by Judge
#include<bits/stdc++.h>
#define db double
using namespace std;
db a,b,c,d,l,r;
inline db f(db x){return (c*x+d)/(a*x+b);}
inline db simpson(db l,db r){ db mid=(l+r)/2;
    return (f(l)+f(r)+4*f(mid))*(r-l)/6;
}
db asr(db l,db r,db eps,db ans){
    db mid=(l+r)/2,L=simpson(l,mid),R=simpson(mid,r);
    if(fabs(L+R-ans)<=eps) return L+R+(L+R-ans);
    return asr(l,mid,eps/2,L)+asr(mid,r,eps/2,R);
}
inline db asr(db l,db r,db eps){
    return asr(l,r,eps,simpson(l,r));
}
int main(){ scanf("%lf%lf%lf%lf%lf%lf",&a,&b,&c,&d,&l,&r);
    return !printf("%.6lf\n",asr(l,r,1e-8));
}

原文地址:https://www.cnblogs.com/Judge/p/10927547.html

时间: 2024-11-03 01:19:51

自适应辛普森了解一下的相关文章

UVA 1356 - Bridge(自适应辛普森)

UVA 1356 - Bridge 题目链接 题意:一个桥长为B,桥上建电线杆,杆高为H,两杆之间距离不超过D,电线杆总长为L,杆子都是等距的,现在建最少的电线杆,问这时候电线离地面高度是多少 思路:二分高度,求出电线长,判断长度够不够即可,那么问题就变成怎么求弧长 求弧长公式为∫w/201+(f′(x)2)??????????√, 建立坐标系使得f(x)=ax2,带入点(w/2, h)求出a,得到方程 那么问题就变成怎么求这个积分了 利用辛普森自适应法,去求即可 代码: #include <c

【自适应辛普森积分】hdu1724 Ellipse

Ellipse Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2502    Accepted Submission(s): 1126 Problem Description Math is important!! Many students failed in 2+2's mathematical test, so let's AC

自适应辛普森法

Simpson公式 设\(f(x)\)为原函数,$g(x)=Ax2+Bx+C $ 为拟合后的函数,则有: \[ \int_{a}^{b}f(x)dx \approx \int_{a}^{b}Ax^2+Bx+C = \frac{A}{3}(b^3-a^3)+\frac{B}{2}(b^2-a^2)+C(a-b) =\frac{(b-a)}{6}(f(a)+f(b)+4f(\frac{a+b}{2})) \] 然后就得到了Simpson公式 \[ \int_{a}^{b}f(x)dx \approx

P4525 【模板】自适应辛普森法1

P4525 [模板]自适应辛普森法1 1 #include <bits/stdc++.h> 2 using namespace std; 3 const double eps = 1e-6; 4 double a, b, c, d, l, r; 5 inline double f(double x) { 6 return (c*x+d)/(a*x+b); 7 } 8 inline double simpson(double l, double r) { 9 double mid = (l+r)

[BZOJ1502]月下柠檬树(自适应辛普森积分)

1502: [NOI2005]月下柠檬树 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1387  Solved: 739[Submit][Status][Discuss] Description 李哲非常非常喜欢柠檬树,特别是在静静的夜晚,当天空中有一弯明月温柔地照亮地面上的景物时,他必会悠闲地 坐在他亲手植下的那棵柠檬树旁,独自思索着人生的哲理.李哲是一个喜爱思考的孩子,当他看到在月光的照射下 柠檬树投在地面上的影子是如此的清晰,马上想到了一个问

BZOJ 1502 NOI 2005 月下柠檬树 计算几何 自适应辛普森积分

题目大意:有一个由圆锥和圆台组成的柠檬树,在月亮发出的平行光下,可以形成一个影子,求这个影子的面积. 思路:理解投影的性质:只要是平行光线,投影在水平面上,所得的图形都与原图形全等. 知道了这一点我们就可以画画图,分析就知道,其实柠檬树的影子,就是一些园和等腰梯形的面积的并.(如下图,样例) 运用计算几何的知识就可以得到圆的方程和圆的公切线的方程,然后得到一个连续的函数.最后这个题就成为一直函数的解析式,求这个函数与X轴之间的面积. 套用辛普森积分:Simpson(l,r) = (F(l) +

Acdream 1234 Two Cylinders 自适应辛普森

题目链接:点击打开链接 给定r1,r2 表示2个圆柱体的半径 这两个圆柱体高是正无穷,互相垂直,问相交的最大面积 #include <stdio.h> #include <string.h> #include <iostream> #include <cmath> #define M 410 #define inf 0x3f3f3f3f const double eps = 1e-8; template <class T> inline bool

自适应辛普森 代码

#include<iostream>#include<cmath>#include<stdlib.h>#include<algorithm>using namespace std;double f(double x)//函数{ return 2*x;}double simpson(double a,double b)//[a,b]区间simpson{ double c=a+(b-a)/2.0; return (f(a)+4*f(c)+f(b))*(b-a)/

算法学习:自适应辛普森

[定义] [定积分] [解决问题] 在计算机中计算出定积分的值,有可能有直接的数学题,也有可能应用到其他方面 主要就是算定积分的值(摊手) [算法分析] 实际上就是尝试得到一个 定积分 f(x)函数约等于 定积分 g(x) 函数 而令g(x)为一个二项式 Ax^2 +Bx + c ,然后我们直接对他进行定积分得到公式 这个对这个函数在区间[a,b]区间上的积分,不断细分最终会得到一个无限接近答案的值 而在题目中,往往会有最后输出的精度要求 所以我们只需要让最终的结果满足这个精度要求即可 有点问题