HDU 2298 Toxophily 【二分+三分】

时间:2020-11-30 21:02:11

一个人站在(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-;
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/;
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=,r=a,mid;
while(r-l>eps){
mid=(l+r)/;
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\n");
else if(fabs(y-h)<=eps)
printf("%.6f\n",ans);
else{
ans=bin(ans);
printf("%.6f\n",ans);
}
}
return ;
}