做题感悟:这题值得注意的一点是 cos(x)中的 x 必须是弧度,发现数学和物理全忘了。
解题思路:
设苹果的位置为【px,py】左图是枚举了0-90区间内角度发射时其轨迹在px点上的y值,最大y值对应一个角度K,右图的x轴是0-90,y轴是对应角度时其轨迹在px点上的y值。由左图的可知0-90区间内角度发射时其轨迹在px点上的值y是 呈现右图的凸性函数。从而射到苹果的值有两个,分别为如右图的两个叉点,而题目要求的min点即为左边那个打叉的点。
X = V*cos(a)*t ;
Y = V*sin(a)*t - 1/2*g*t*t ;
消去 t 可得 Y=X * sin( a ) / cos( a ) - X * X * g / ( 2.0 * V * V * cos( a ) * cos( a ) .
物理知识(抛物线): 水平方向 x = v * t . 竖着方向 v = g * t . y = 1/2* g * t ^ 2 . y = v * t - 1/2 * g * t ^2 . V1^2 - V^2 = 2*g*h (V1为末速度,V2为初速度).
代码:
#include<stdio.h> #include<iostream> #include<map> #include<string> #include<string.h> #include<stdlib.h> #include<math.h> #include<queue> #include<algorithm> using namespace std ; const double eps = 0.00000001 ; const double PI = 3.1415926 ; const double g = 9.8 ; double rx,ry,v,y ; double find(double a) // a为弧度 { return rx*sin(a)/cos(a)-rx*rx*g/(2.0*v*v*cos(a)*cos(a)) ; } double third_search(double le,double rt)// 三分找最大值 { double mid,midd,y1,y2 ; while(rt-le>=eps) { mid=(le+rt)/2.0 ; midd=(mid+rt)/2.0 ; y1=find(mid) ; y2=find(midd) ; if(y1 < y2) le=mid ; else rt=midd ; } y=(y1+y2)/2.0 ; return (le+rt)/2.0 ; } double binary_search(double le,double rt)// 二分找最优解 { double mid ; while(rt-le>=eps) { mid=(le+rt)/2.0 ; if(find(mid)<ry) le=mid ; else rt=mid ; } return mid ; } int main() { int T ; scanf("%d",&T) ; while(T--) { scanf("%lf%lf%lf",&rx,&ry,&v) ; double angle=third_search(0,PI/2.0) ; if(ry>y) // 如果最大 y 值小于已知 ry 则无解。 { printf("-1\n") ; continue ; } printf("%.6lf\n",binary_search(0,angle)) ; } return 0 ; }