uva1356 - Bridge 自适应simpson公式

A suspension bridge suspends the roadway from huge main cables, which extend from one end of the bridge to the other. These cables rest on top of high towers and are secured at each end by anchorages. The towers enable the main cables to be draped over long distances.

Suppose that the maximum distance between two neighboring towers is D, and that the distance from the top of a tower to the roadway is H. Also suppose that the shape of a cable between any two neighboring towers is the same symmetric parabola (as shown in the figure). Now given B, the length of the bridge and L, the total length of the cables, you are asked to calculate the distance between the roadway and the lowest point of the cable, with minimum number of towers built (Assume that there are always two towers built at the two ends of a bridge).

\epsfbox{p3485.eps}

Input 

Standard input will contain multiple test cases. The first line of the input is a single integer T (1$ \le$T$ \le$10) which is the number of test cases. T test cases follow, each preceded by a single blank line.

For each test case, 4 positive integers are given on a single line.

D
- the maximum distance between two neighboring towers;
H
- the distance from the top of a tower to the roadway;
B
- the length of the bridge; and
L
- the total length of the cables.

It is guaranteed that B$ \le$L. The cable will always be above the roadway.

Output 

Results should be directed to standard output. Start each case with "Case #:" on a single line, where # is the case number starting from 1. Two consecutive cases should be separated by a single blank line. No blank line should be produced after the last test case.

For each test case, print the distance between the roadway and the lowest point of the cable, as is described in the problem. The value must be accurate up to two decimal places.

Sample Input 

2

20 101 400 4042

1 2 3 4

Sample Output 

Case 1:
1.00

Case 2:
1.60

  桥上摆放等距的塔,塔高H,相邻的塔距离不超过D,塔之间绳子是抛物线。桥长B,绳子总长L,求建最少的塔时绳子下端离地的高度。

  塔数目最小时,间隔数为ceil(B/D),每个间隔的宽度D1=B/n,每段绳子长L1=L/n。设每段绳子宽度为w,高h,抛物线方程f(x)=ax^2=4h/(w^2),二分枚举h,知道算出的抛物线长度为L1,最后答案就是H-h。

  问题就在于抛物线长度怎么算。弧长积分公式∫a到b√(1+(f'(x))^2),可以积出来,但是不会积的话就可以用simpson公式。

  递归算左右两部分的simpson值,如果和整体的simpson值误差小到一定精度就返回。

  有一点不明白的是白书上的那个误差小于15eps就返回L+R+误差/15,为什么这样就能保证误差小于eps。。

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<stack>
#define INF 0x3f3f3f3f
#define MAXN 10010
#define MAXM 110
#define MOD 1000000007
#define MAXNODE 4*MAXN
//#define eps 1e-9
using namespace std;
typedef long long LL;
int T,D,B,H,L;
double a;
//simpson公式用到的函数
double F(double x) {
  return sqrt(1+4*a*a*x*x);
}
//三点simpson法。这里要求F是一个全局函数
double simpson(double a, double b) {
  double c=a+(b-a)/2;
  return (F(a)+4*F(c)+F(b))*(b-a)/6;
}
//自适应Simpson公式(递归过程)。已知整个区间[a,b]上的三点simpson值A
double asr(double a, double b, double eps, double A) {
  double c= a+(b-a)/2;
  double L=simpson(a,c),R=simpson(c,b);
  if(fabs(L+R-A)<=15*eps) return L+R+(L+R-A)/15;
  return asr(a,c,eps/2,L) + asr(c,b,eps/2,R);
}
//自适应Simpson公式(主过程)
double asr(double a,double b,double eps) {
  return asr(a,b,eps,simpson(a,b));
}

// 用自适应Simpson公式计算宽度为w,高度为h的抛物线长
double parabola_arc_length(double w, double h) {
  a=4.0*h/(w*w); // 修改全局变量a,从而改变全局函数F的行为
  return asr(0,w/2,1e-9)*2;
}
int main(){
    freopen("in.txt","r",stdin);
    int cas=0;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d%d%d",&D,&H,&B,&L);
        int n=(B+D-1)/D;
        double D1=(double)B/n,L1=(double)L/n,l=0,r=H;
        while(r-l>1e-9){
            double mid=l+(r-l)/2;
            if(parabola_arc_length(D1,mid)<L1) l=mid;
            else r=mid;
        }
        printf("Case %d:\n%.2lf\n",++cas,H-l);
        if(T) puts("");
    }
    return 0;
}


### 回答1: 自适应Simpson积分是一种数值积分方法,可以用于计算函数在给定区间上的积分值。在Matlab中,可以使用内置函数“quad”来实现自适应Simpson积分。具体步骤如下: 1. 定义被积函数f(x)。 2. 使用“quad”函数进行积分计算,语法为: quad(f,a,b) 其中,f为被积函数,a和b为积分区间的上下限。 3. 如果需要更高的精度,可以使用“quadl”函数进行积分计算,语法为: quadl(f,a,b,tol) 其中,tol为误差容限,即当积分误差小于tol时,积分计算停止。 需要注意的是,自适应Simpson积分方法适用于连续函数,如果被积函数在积分区间上不连续或有间断点,需要进行分段积分。 ### 回答2: 自适应Simpson积分是一种常用的数值积分方法,它基于辛普森公式,能够在不同精度要求下,自适应地选取合适的分割数,从而达到更高的精度。在Matlab中实现自适应Simpson积分需要以下步骤: 1. 编写Simpson积分的函数subSimpson,该函数接受一个函数句柄和积分上下限为参数,返回积分值。 2. 设置初始的精度要求tol和分割数N0。将整个积分区间[a,b]均匀地分割成N0个子区间,计算每个子区间的积分值,求和得到这一级别的积分结果S1。 3. 将整个积分区间再次均匀地分割,得到2N0个子区间。根据辛普森公式计算每个子区间的积分值,并利用这些结果得到更加精细的积分值S2。 4. 计算收敛因子Q=(S2-S1)/15,如果Q小于指定的精度要求tol,则返回S2作为积分结果;否则,将积分区间再次分割,进入第三步。 5. 在分割过程中,可以记录下每一级别的积分值和分割数,以便于后续的分析和统计。 Matlab代码示例: ```matlab function [I,n] = adaptSimpson(f,a,b,tol,N0) % f: 被积函数 % a,b: 积分区间 % tol: 精度要求 % N0: 初始分割数 x = linspace(a,b,2*N0+1); h = (b-a)/N0/2; y = f(x); S1 = sum(y(1:2:end-2)+4*y(2:2:end-1)+y(3:2:end)); S2 = sum(y(1:2:end-2)+4*y(2:2:end-1)+2*y(3:2:end-1)+4*y(4:2:end)+y(5:2:end)); I = S2/15*h; n = N0; Q = (S2-S1)/15; while abs(Q) > tol N = 2*n; x = linspace(a,b,2*N+1); y = f(x); S1 = S2; S2 = sum(y(1:2:end-2)+4*y(2:2:end-1)+2*y(3:2:end-1)+4*y(4:2:end)+y(5:2:end)); I = S2/15*h; n = N; Q = (S2-S1)/15; end end ``` 代码中,我们先根据初始的分割数N0,计算出积分区间的所有节点x,并根据辛普森公式计算出这一级别的积分结果S1和下一级别的积分结果S2。如果S2满足精度要求,则直接返回;否则,我们将分割数翻倍,重新计算节点和积分结果,进入下一级别的计算。当S2满足精度要求后,我们返回积分结果I和分割数n。 总之,自适应Simpson积分是一种高效的数值积分方法,通过递归的方式自适应地调整分割数,从而实现更高的精度。在Matlab中实现自适应Simpson积分,需要熟悉辛普森公式和递归算法的基本原理。 ### 回答3: 自适应Simpson积分是一种数值积分方法,可用于计算函数的定积分。该方法是通过将定积分区间分割成若干个子区间,每个子区间采用Simpson公式来计算积分值,从而得到整个区间的积分值。与传统的Simpson积分相比,自适应Simpson积分可以更准确地估计积分值,且能够自动适应积分函数的变化以提高计算效率。 在Matlab中,实现自适应Simpson积分的基本思路如下: 1. 将积分区间[a,b]分割成若干个子区间,每个子区间采用Simpson公式计算积分值I1。 2. 将整个区间[a,b]再分割成若干个子区间,每个子区间采用两个子区间的Simpson积分值之和减去一个子区间的Simpson积分值来计算积分值I2。 3. 计算误差E=abs(I2-I1)/15,如果E大于预设的误差精度tolerance,则将整个区间继续分割,否则返回I2作为最终的积分值。 该方法的优点在于能够自动适应积分函数的变化,从而提高计算精度和效率。具体实现时,需要使用递归方法来实现自动区间分割,同时需要设置适当的最大分割次数以避免程序陷入死循环。 Matlab中自适应Simpson积分的函数形式如下: function[result, err] = adaptive_simpson(f, a, b, tolerance, max_depth) % f为要积分的函数,a和b为积分区间的下限和上限,tolerance为误差精度,max_depth为最大分割次数 depth = 1; % 初始化分割次数为1 [result, err] = simpson_rule(f, a, b); % 计算初始的积分值和误差 while (depth < max_depth) && (err > tolerance) % 如果分割次数未达到最大值且误差仍然大于误差精度 depth = depth + 1; % 分割次数加1 [result_left, err_left] = simpson_rule(f, a, (a+b)/2); % 计算左半区间的积分值和误差 [result_right, err_right] = simpson_rule(f, (a+b)/2, b); % 计算右半区间的积分值和误差 result = result_left + result_right; % 计算整个区间的积分值 err = err_left + err_right; % 计算整个区间的误差 end 其中simpson_rule函数为Simpson积分公式的实现,具体如下: function[result, err] = simpson_rule(f, a, b) % f为要积分的函数,a和b为积分区间的下限和上限 result = (b-a)/6 * (f(a) + 4*f((a+b)/2) + f(b)); % 计算Simpson积分值 err = (b-a)^5 / 2880 * max(abs(diff(f([a,b,(a+b)/2])))); % 计算误差 end 需要注意的是,在实现自适应Simpson积分时,需要确保积分函数在积分区间内具有充分的平滑性和连续性,否则可能导致计算误差过大或发生计算异常。因此在应用该方法时,需要首先对积分函数进行充分的分析和预处理,以保证计算结果的准确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值