G57 自适应辛普森积分

视频链接:https://www.bilibili.com/video/BV1mv4y1G78Q/

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

自适应辛普森法

  1. 任意可积函数分割成很多段,每段就可以用二次函数来拟合,套用辛普森公式进行近视计算。
  2. 对积分区间不断二分,每次判断当前段和二次函数的相似程度,如果足够相似就直接代入辛普森公式计算,否则将当前段分割成左右两段递归求解。
  3. 如何判断当前段和二次函数是否相似? 把当前段直接代入公式求积分,再将当前段从中点分割成两段,把这两段再直接代入公式求积分。如果当前段的积分和分割成两段后的积分之和相差很小,就可以认为当前段和二次函数很相似了,不用再递归分割了。

分割递归次数与区间宽度 n、精度 eps 有关
时间复杂度:𝑂(𝑙𝑜𝑔(𝑛/𝑒𝑝𝑠))

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const double eps=1e-10;
double a,b,c,d,l,r;

double f(double x){ //积分函数
  return (c*x+d)/(a*x+b);
}
double simpson(double l,double r){//辛普森公式
  return (r-l)*(f(l)+f(r)+4*f((l+r)/2))/6;
}
double asr(double l,double r,double ans){//自适应
  auto m=(l+r)/2,a=simpson(l,m),b=simpson(m,r);
  if(fabs(a+b-ans)<eps) return ans;
  return asr(l,m,a)+asr(m,r,b);
}
int main(){
  scanf("%lf%lf%lf%lf%lf%lf",&a,&b,&c,&d,&l,&r);
  printf("%.6lf",asr(l,r,simpson(l,r)));
  return 0;
}

2. Luogu P4526 【模板】自适应辛普森法 2

估算一下积分上限
条件:𝑎=50,eps=10^(−10)
𝑥=10 时,f(𝑥)=10^(5−10)=10^(−5)>eps, 
𝑥=20 时,f(𝑥)=20^(2.5−20)=20^(−17.5)<eps, 
所以 [0,+∞] 转化为 [eps,20]

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const double eps=1e-10;
double a,l,r;

inline double f(double x){ //积分函数
  return pow(x,(a/x)-x);
}
double simpson(double l,double r){//辛普森公式
  return (r-l)*(f(l)+f(r)+4*f((l+r)/2))/6;
}
double asr(double l,double r,double ans){//自适应
  auto m=(l+r)/2,a=simpson(l,m),b=simpson(m,r);
  if(fabs(a+b-ans)<eps) return ans;
  return asr(l,m,a)+asr(m,r,b);
}
int main(){
  scanf("%lf",&a);
  if(a<0) return printf("orz"),0;
  printf("%.5lf",asr(eps,20,simpson(l,r)));
  return 0;  
}

3. HDU1724 Ellipse

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const double eps=1e-10;
double a,b,l,r;

inline double f(double x){ //积分函数
  return b*sqrt(1-(x*x)/(a*a));
}
double simpson(double l,double r){//辛普森公式
  return (r-l)*(f(l)+f(r)+4*f((l+r)/2))/6;
}
double asr(double l,double r,double ans){//自适应
  auto m=(l+r)/2,a=simpson(l,m),b=simpson(m,r);
  if(fabs(a+b-ans)<eps) return ans;
  return asr(l,m,a)+asr(m,r,b);
}
int main(){
  int t; scanf("%d",&t);
  while(t--){
    scanf("%lf%lf%lf%lf",&a,&b,&l,&r);
    printf("%.3lf\n",2*asr(l,r,simpson(l,r)));
  }
}

 

练习:

Luogu P4207 [NOI2005] 月下柠檬树

Luogu CIRU - The area of the union of circles

posted @ 2023-02-27 16:02  董晓  阅读(213)  评论(0编辑  收藏  举报