题意:
n≤10个障碍物,一个球从起点弹到终点,距离为d≤10000,反弹次数b≤15,重力g=1,不计中间过程的能量损失(理想模型),求可以越过所有障碍物最小的初速度是多少?
做法:
暴力法,对每个弹跳次数搜索所有障碍高,通过p, h, d求初速度。
对于上图中弹跳2次的情况,我们可以看作是3个一模一样的抛物线,因为是理想模型,而又必须从起点跳到终点。这样我们就可以通过取模来直接处理所有的抛物线。
对于弹跳次数b,每个相同抛物线的宽度为d /(b+1),设为x0。那么对于每个障碍将他们的水平距离 p,p%x0即可将他们都移到过原点的抛物线来计算。因为x0不一定是整数,需要自己写一个去模函数。
设p为障碍水平距离,h为障碍高,则由以下两个公式可得:
Vy^2 = g*x0*x0*h / 2p(x0 - p)
Vx^2 = g*g*x0*x0 / 4Vy*Vy
对于每一个弹跳次数b,算出最大的Vy^2+Vx^2作为其V^2,然后在所有的V^2里面找到最小的就是结果。
需要注意的是如果Vy^2小于Vx^2,那么出射角小于45度,这种情况下最小的v是在45度时取到的,即Vx^2=Vy^2=g*x0 / 2。(由公式2可得)
反省:
1)特判碰到障碍物的情况。
通过样例发现球有可能刚好落在障碍物所在的点。
当时没有考虑到的:
2)x0不一定是整数,需要自己写一个去模函数。
3)如果Vy^2小于Vx^2,那么出射角小于45度,这种情况下最小的v是在45度时取到的。
代码:
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define EXP 0.00000001
#define INF 1e17
struct
ob {
double p,h;
};
double // double取模
mod(double a,double b) {
if (a<b) return a;
int t=floor(a/b);
return (a-b*t);
}
int
main(){
int n,b,d;
double ans;
while(cin>>d>>n>>b) {
ob c[11];
for(int i=0;i<n;i++)
cin>>c[i].p>>c[i].h;
double maxx,minn=INF,vx2,vy2;
for(int i=0;i<=b;i++){
maxx=0;
double x0=(d*1.0)/(i+1.0);
bool yep=1;
for(int j=0;j<n;j++){
double p=mod(c[j].p,x0);
double h=c[j].h;
if (fabs(p-0)<EXP) {yep=0;break;} // 球落在障碍物处
maxx=max(maxx,x0*x0*h/(2.0*p*(x0-p)));
}
if (!yep) continue;
vy2=maxx;
vx2=x0*x0/(4.0*vy2);
if (vx2>vy2) vx2=vy2=x0/2.0; // 45度
minn=min(vy2+vx2,minn);
}
ans=sqrt(minn);
printf("%.5lf\n",ans);
}
}