求影子的最大长度,可以把它当数学题进行分类讨论,也可以用三分法来近似求解。
用数学方法来解题的时候容易碰到一些陷阱。
后来看了kuang bin 大神的代码之后,才把问题考虑周全。
数学公式法(分类讨论) :
#include <stdio.h>
#include <math.h>
double H,h,D;
double Min;
double func(double x) {
return (H+D-x)-(H-h)*D/x;
}
int main() {
int n;
scanf("%d",&n);
for ( int i = 0 ; i < n ; i ++ )
{
scanf("%lf%lf%lf",&H,&h,&D);
double t1 = sqrt((H-h)*D);
double t2 = (H-h)*D/H;
if ( t1 >= D ) /* 当t1 >= D时,首先函数func取不到极大值。
同时推出 h*D/H <= h*D/(D+h), 得 h/(1+h/D) < h , 即只有当人贴在墙上时
才有最长的影子。 */
printf("%.3f\n",h);
else if ( t2 >= t1 ) // 当t2 >= t1 时,影子不会出现在墙上。
printf("%.3f\n",h*D/H);
else
printf("%.3f\n",func(t1));
}
return 0;
}
三分法:
#include <stdio.h>
#include <math.h>
//三分法
double H,h,D;
const double eps = 1e-9;
double fun(double x) {
return (H+D-x)-(H-h)*D/x;
}
void solve(double l , double r) {
double m1,m2;
double d1,d2;
while (r-l>=eps)
{
double length = r-l;
m1 = l + length / 3;
m2 = l + length *(2.0/3);
d1 = fun(m1);
d2 = fun(m2);
if ( d1 >= d2 )
r = m2;
else
l = m1;
}
printf("%.3f\n",d1);
}
int main() {
int n;
scanf("%d",&n);
for ( int i = 0 ; i < n ; i ++ )
{
scanf("%lf%lf%lf",&H,&h,&D);
solve((H-h)*D/H,D);
}
return 0;
}