天天看点

zoj2614 Bridge(自适应Simpson公式+二分答案)

【题解】

首先求出分出的最少区间数:n=ceil(B/D),ceil():向上取整

然后依据每一段的宽度w=B/n及弧长L/=n来求"深度"h即可,答案为:y=H-h

w,h可确定一条抛物线,其弧长L关于h单调递增,考虑二分h,验证弧长

设抛物线顶点为原点,由(w/2,d)在抛物线上可知其方程为:y=a*x^2,其中a=4*h/(w*w)

可导函数f(x)在区间[a,b]上的弧长:有公式(无法打出来),可以用微元法来推导,公式中的积分部分用自适应Simpson公式来求

【代码】

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
double w,h,_a;//_a:设 F(x)=_a*x^2
double F(double x)
{
	return sqrt(1+4*_a*_a*x*x);
}
double simpson(double a,double b)//三点simpson法 
{
	double c=(a+b)/2;
	return (b-a)/6*(F(a)+4*F(c)+F(b));
}
double asr(double a,double b,double eps,double A)//递归过程 
{
	double c=(a+b)/2,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);
}
int main()
{
	double H,L,left,right;
	int T,D,B,n,i;
	scanf("%d",&T);
	for(i=1;i<=T;i++)
	{
		scanf("%d%lf%d%lf",&D,&H,&B,&L);
		n=(B+D-1)/D;//平均分成的段数 
		L/=(double)n;//每段绳索长 
		w=(double)B/(double)n;//每段宽度 
		left=0;
		right=H;
		while(right-left>1e-4)//二分桥的"深度"h==H-y
		{
			h=(left+right)/2;
			_a=4*h/(w*w);
			if(2*asr(0,w/2,1e-4,simpson(0,w/2))<=L) left=h;
			else right=h;
		}
		if(i>1) printf("\n");
		printf("Case %d:\n%.2lf\n",i,H-h);
	}
	return 0;
}