acdreamer 1221&&sgu204 (三分)

题目链接:传送门

题意:给出b1,t1,b2,t2,l,ds,df,和重力加速的g,左边黑点表示起点,右边黑点表示终点,你可以从起点以任意角度、任意速度投出一个小球,从t1,b1中穿过去,落在l上,然后再重新在落点以任意角度、任意速度投出这个球然后从t2,b2中间穿过去于终点落地,然后求两次投掷速度中的最大值的最小值是多少,也就是MIN(MAX(v1,v2))。

分析:首先我们会发现以在l中间的落脚点为自变量,答案是一个单峰函数,存在最小值.
然后这样我们就可以三分答案去求落脚点了,但是要注意精度,应该这样while(high-low>1e-12)注意精度
然后就是对两次投掷分开求最小速度,最重要的是在求解这个抛物线方程。
对于一次投掷,我们很容易发现45°投出是初速度最小的(其实是生活常识啊),然后由于投掷是一个抛物线,假设以投掷点为原点,然后以落脚点坐标x0,那么45°的解析式就是 y=-1/x0*x(x-x0),然后我们判断以45°投出时是否会触碰到上下界,如果触碰到了,很容易脑补出只需要将角度刚好调整到上下界的高度,再求解出来抛物线方程就行了。本题抛物线方程采用y=a*x*(x-x0);

代码如下:

#include <set>
#include <map>
#include <stack>
#include <queue>
#include <math.h>
#include <vector>
#include <string>
#include <utility>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <functional>

using namespace std;
const double pi=acos(-1);
const int maxn=100005;
const int INF=0x3f3f3f;
const double eps=1e-12;
int dcmp(double x){
    if(fabs(x)<eps)return 0;
    if(x>0)return 1;
    return -1;
}//精度为eps的比较
double b1,t1,b2,t2,l,ds,df,g;
double calu(double dis,double x,double b,double t){
    double v=0;
    double mid=dis/2;
    double a=-1/dis;
    double y=a*x*x+x;
    if(y>=b&&y<=t){
        double h=a*mid*mid+mid;
        double t,vx,vy;
        t=sqrt(2*h/g);
        vx=dis/t/2;
        vy=g*t;
        v=vx*vx+vy*vy;
    }
    else{
        if(y<b)
        a=b/(x*x-dis*x);
        else
            a=t/(x*x-dis*x);
        double h=a*mid*(mid-dis);
        double t,vx,vy;
        t=sqrt(2*h/g);
        vx=dis/t/2;
        vy=g*t;
        v=vx*vx+vy*vy;

    }
    return v;
}
double solve(double t){
    double ans1=ds+t;
    double ans2=df+l-t;
    double v1,v2;
    v1=calu(ans1,ds,b1,t1);
    v2=calu(ans2,l-t,b2,t2);
    return max(v1,v2);
}
int main(){
    while(scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&b1,&t1,&b2,&t2,&l,&ds,&df,&g)!=EOF){
        double low,high,mid,midd;
        low=0;
        high=l;
        while(high-low>eps){
            mid=(high+low*2)/3;
            midd=(low+high*2)/3;
            if(solve(mid)<solve(midd))high=midd;
            else low=mid;
        }
        printf("%.4f\n",sqrt(solve(mid)));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值