Appoint description:
Description
Input
Output
Sample Input
100 1 0 50 100
Sample Output
14.57738
题目真的很长很啰嗦。然后后面的公式虽然有用,但是都可以推导出来,还有一些要注意的东西,基本都是细节。真是读题半天。Oops,真是英语渣渣。
大意是发射子弹,有平行速度Vx和垂直速度Vy,求他们的最小速度V=sqrt(Vx^2+Vy^2)。有一个目标点。子弹允许无损耗反弹,但是有反弹次数。然后起始点和目标点中间有n个障碍物,没个障碍物都有他们的高度,当然子弹不能穿透障碍物,只能从头上越过。恩,题意就是这样了。
题解:枚举反弹次数,从0次到t次。每次都能知道子弹抛物线的最长距离l=d/(i+1),然后可以把Vx表示出来l/(2*Vy).然后枚举每个障碍物,求得满足越过所有障碍物的最小垂直速度Vy.然后就可以求出Vx,这里需要注意一下的就是我们要求的结果是求最小的V,这里Vy和Vx的大小关系要搞明白,就是当Vy比Vx小的时候,可以使Vy更大更接近Vx,这样使得我们的V更小。就是这里WA了几发,好不应该。
#include<limits>
#include<queue>
#include<vector>
#include<list>
#include<map>
#include<set>
#include<deque>
#include<stack>
#include<bitset>
#include<algorithm>
#include<functional>
#include<numeric>
#include<utility>
#include<sstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<ctime>
#define LL __int64
#define eps 1e-8
#define pi acos(-1)
#define INF 0x7fffffff
#define delta 0.98 //模拟退火递增变量
using namespace std;
struct point{
double x,y;
};
point a[20];
int dcmp(double x){
if (fabs(x)<=eps) return 0;
if (x>0) return 1;
else return -1;
}
int main(){
double d;
int n,m,i,j;
scanf("%lf%d%d",&d,&n,&m); //目标在d点,有n个障碍,最多只能跳m次
for (i=0;i<n;i++)
scanf("%lf%lf",&a[i].x,&a[i].y);//障碍的位置和高度
double ans=INF;
for (i=0;i<=m;i++){ //i代表反弹几次
double l=d/(i+1); //代表一个抛物线的最长距离
double vy=0;
int f=0;
for (j=0;j<n;j++){
double x=a[j].x;
double y=a[j].y;
while (dcmp(x-l)>=0)
x-=l;
if (dcmp(x)==0){ //障碍物正好在反弹点上
f=1;
break;
}
double v1=l*sqrt(y/(2*x*(l-x)));
if (dcmp(v1-vy)>=0) vy=v1;
}
if (f) continue;
double vx=l/2.0/vy;
double s;
if (dcmp(vx-vy)>=0)
vx=vy=sqrt(l/2.0);
s=sqrt(vx*vx+vy*vy);
if (dcmp(ans-s)>=0) ans=s;
}
printf("%.5f\n",ans);
return 0;
}