题意:高度为H的灯泡固定,有一面墙距离灯泡水平D,一个高度h的人站在灯和墙之间移动,问人的影子的最长距离为多少?
思路:训练时卡在了这个题上面,实际上就是一个初中水平的几何题,作几条辅助线,我们设人与灯的水平距离为x,在影子没有射到墙上之前,离灯越远影子越长,所以我们只考虑影子恰好射到墙上到影子与墙重合的过程,可以计算出墙上的影子的长度为 H-D*(H-h)/ x,地上的影子为D - x,x的取值范围为D - D* h/H 到 D,影子的总长度随x的变化符合2次函数,我们可以采取三分求最值,也可以发现这是一个对号函数,根据对号函数的性质求最值简单一些
看了学长的写法,这个题还可以暴力

三分:
#include <iostream>
#include <cstdio>
const double exp = 1e-9;
double H,h,D;
double cal(double x){
return D - x + H - (H - h) * D / x;
}
int main(void){
int t;
scanf("%d",&t);
while(t--){
scanf("%lf%lf%lf",&H,&h,&D);
double l = D - h / H * D;
double r = D;
while(r - l >= exp){
double mid = (l + r) / 2;
double midd = (r + mid) / 2;
if(cal(mid) > cal(midd)){
r = midd;
}
else{
l = mid;
}
}
//printf("%.3lf\n",l);
printf("%.3lf\n",cal(l));
}
} 利用对号函数性质
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdio>
using namespace std;
double H,h,D;
double cal(double x){
return D - x + H - D * (H - h) / x;
}
int main(void){
int t;
cin >> t;
while(t--){
cin >> H >> h >> D;
double x = sqrt(D * (H - h));
if(x >= D - D * h / H && x <= D){
printf("%.3lf\n",H + D - 2 * x);
}
else{
printf("%.3lf\n",max(cal(D - D * h / H ),cal(D)));
}
}
return 0;
}
一道结合几何知识与三分搜索算法的题目,描述了一个高度为H的灯泡、距离灯泡水平D的墙以及一个高度为h的人如何寻找影子最长的情况。当人与灯的水平距离x变化时,影子的总长度会形成一个2次函数,通过三分法求解函数最大值,找到最长影子的长度。
&spm=1001.2101.3001.5002&articleId=80022174&d=1&t=3&u=0de44d1583044f4d94ab4ce4d67dec87)
345

被折叠的 条评论
为什么被折叠?



