灯泡与影子(三分)

题目描述:

有一天,小明发现他的影子长度随着他在灯泡和墙壁之间走动时会发生变化,一个突发奇想在他的脑海里闪过,他现在想知道他来回走动,他的影子的最大长度是多少?

输入格式:

第一行包含一个整数T (T <= 100),表示测试数据的级数。

对于每组测试数据仅一行包含三个实数 Hh 和 D。 H 是灯光的高度, h小明的身高,D是灯光和墙壁的水平距离三个数的范围都在 10-2 到 103之间 ,   H - h >= 10-2。

输出格式:

共T行,每组测试数据占一行,表示影子的长度,保留三位小数。

样例输入:

3
2 1 0.5
2 0.5 3
4 3 4

样例输出:

1.000
0.750
4.000

提示:

三分的模板:

double l = 0, r = 1e9;
while (r-l >= 1e-3) {
	double m1 = l+(r-l)/3,  m2 = r-(r-l)/3;
	if (  f(m1) < f(m2) )  l = m1;
	else r = m2;
}

时间限制: 1000ms
空间限制: 256MB

题解:

求人从左向右走动时,影子的长度L的最大值

人在灯下的影子长度是0,这时他如果向前走的话,影子会逐渐变长,到最后人走到墙的位置的时候,影长度便是人的身高了,所以影长的变化曲线要么是单调递增的,并且是向上凸的,所以适合三分。(二分法作为分治中最常见的方法,适用于单调函数,逼近求解某点的值,当函数是凸性函数时,就得用三分)。

由于影长从灯下0一直到恰好没投影到墙上的过程是一个单调的过程,我们可以直接求更新答案。用三分算法求解投影到墙上后影长的变化即可。

 

代码如下:

#include<cstdio>
double H,h,D;
double f(double m){
	double a=(H-h)/(m-D),b=H+a*D;
	if(b>=0) return b+m;
	else return -b/a+m;
}
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%lf %lf %lf",&H,&h,&D);
		double l=0,r=D;
		while(r-l>1e-5){
			double m1=l+(r-l)/3,m2=r-(r-l)/3;
			if(f(m1)<f(m2)) l=m1;
			else r=m2;
		}
		printf("%.3lf\n",f(l));
	}
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值