题意:多组数据。一个房间里有个灯泡,灯的高度为 ,人的高度为 ,房间宽度为 ,求影子长度 的最大值。
数据范围与约定:
。
解析:这道题其实可以靠推数学公式做的,但是这里着重介绍三分法。
可以发现,人从灯正下方向墙移动,投影在墙上的影子长度递增,而投影在地上的影子长度递减,加起来是一个单峰函数,我们可以三分解决。
现在的问题就是要获知影子长度 与人离灯的距离 的函数关系。
首先我们算地上影子的长度,这个易知是 ;
然后算墙上影子的长度,我们假象在灯和影子最高点处作墙的垂线,如图所示:
这两个三角形相似,根据比例关系,墙上影子的高度为:
所以影子长度的关系式为:
实际上这是个对勾函数,可用数学方法直接计算答案。我们采用三分法,但是要注意定义域的问题。一开始是没有墙上的影子的,地上的影子随着向墙移动长度递增,直到投影点与墙角重合时达到最值。很明显只有地上影子的一段不可能是最优的,所以我们可以更新下限,下限为投影点与墙角重合时人离灯的距离,同理运用相似三角形:
所以定义域为 ,从这里开始三分即可。
#include<stdio.h>
int t;
double H,h,D,eps=1e-9;
double count(double x)
{
double L=(D-x+H)-(H-h)*D/x;
return L;
}
double three_devide(double l,double r)
{
double f1,f2,mid,mmid;
while(r-l>=eps)
{
mid=l+(r-l)/3;
mmid=r-(r-l)/3;
f1=count(mid);
f2=count(mmid);
if(f1>=f2)
r=mmid;
else
l=mid;
}
return f1;
}
int main()
{
int i,j;
scanf("%d",&t);
while(t--)
{
scanf("%lf%lf%lf",&H,&h,&D);
printf("%.3lf\n",three_devide((H-h)*D/H,D));
}
return 0;
}