一个人站在(0,0)处射箭,箭的速度为v,问是否能够射到(x,y)处,并求最小角度。
首先需要判断在满足X=x的情况下最大高度hmax是否能够达到y,根据物理公式可得
h=vy*t-0.5*g*t*t
vx=v*cos(a)
vy=v*sin(a)
t=x/vx
由此可推出:h=x*tan(a)-(g*x*x)/(2*v*v)/cos(a)/cos(a)
g,x,v已知,设A=x,B=(g*x*x)/(2*v*v)
原式化为:h=A*tan(a)+(-B/(cos(a)^2))
由于凸函数有以下性质:
1,如果f和g是凸函数,那么m(x) = max{f(x),g(x)}和h(x) = f(x) + g(x)也是凸函数。
2,如果f和g是凸函数,且g递增,那么h(x) = g(f(x))是凸函数。
tan(a)为凸函数,cos(a)为凸函数,-(1/x)为增凸函数。所以h为凸函数。
以上是h函数是凸函数的证明,因为网上的题解基本都是一句带过,小白的我又看不懂,只能自己证明。若有出错的地方,请大神指出。拜谢。
因此可以三分出hmax。
若能到达,再通过二分得到最小的仰角。
#include<stdio.h> #include<string.h> #include<math.h> const double pi=acos(-1.0),g=9.8,eps=1e-8; double x,y,v; double cal(double a){ double vx=v*cos(a); double vy=v*sin(a); double t=x/vx; double h=vy*t-g*t*t/2; return h; } double thrdiv(){ double l=0.0,r=pi/2.0,lm,rm; while(r-l>eps){ lm=(l*2.0+r)/3.0; rm=(l+r*2.0)/3.0; if(cal(lm)>cal(rm)) r=rm; else l=lm; } return l; } double bin(double a){ double l=0,r=a,mid; while(r-l>eps){ mid=(l+r)/2; if(cal(mid)<y) l=mid; else r=mid; } return l; } int main(){ double ans,h; int t; scanf("%d",&t); while(t--){ scanf("%lf%lf%lf",&x,&y,&v); ans=thrdiv();h=cal(ans); if(y-h>eps) printf("-1 "); else if(fabs(y-h)<=eps) printf("%.6f ",ans); else{ ans=bin(ans); printf("%.6f ",ans); } } return 0; }