计算几何--bnu51638

Air Hockey

Time Limit: 1000ms
Memory Limit: 262144KB
64-bit integer IO format:  %lld      Java class name:  Main
Special Judge
Type: 
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •                   
  • 无聊的过河船同学和无聊的胀鱼同学非常喜欢打桌上冰球(其实只是喜欢听球碰撞时的声音)。在无聊的一天,无聊的过河船同学想到了一个无聊的玩法:两人同时将两个球放桌面上,同时击出,然后听两颗球撞在一起时的声音。然而他们都对击球的精确度把握得不是很好,所以这两颗球并不一定能相撞。

    现在假设桌面无限大,并且绝对光滑,给出两球的初始位置、半径和运动速度,保证两球初始没有接触。无聊的过河船同学想知道两球能否相撞(接触即认为相撞),如果能,他想知道两球相撞的时间(从两人击球时开始计时),如果不能,他想知道全过程中两球距离的最小值,这里两球距离的定义为两球上任取两个点的距离的最小值,数据保证这种情况下答案不小于10^{-6}。请注意,冰球是个圆柱体,从空中往下看就是一个圆,且在这个问题中,冰球的高度可以忽略不计。

    Input

    第一行是一个正整数T(\leq 10000),表示测试数据的组数,

    每组测试数据包含两行,

    i行包含五个绝对值不大于1000的整数x[i],y[i],r[i],vx[i],vy[i],表示第i个球的初始位置、半径和运动速度。

    Output

    对于每组测试数据,若两球能相撞,输出两球相撞的时间,否则输出全过程中两球距离的最小值,相对误差不超过10^{-6}即可,

    也就是说,令输出结果为 a,标准答案为 b,若满足 \frac{ \left | a-b \right | }{max(1,b)} \leq 10^{-6},则输出结果会被认为是正确答案。

    Sample Input

    2
    0 0 2 1 0
    11 0 1 -1 0
    0 0 2 1 0
    11 5 1 -1 0

    Sample Output

    4.0000000000
    2.0000000000

    Hint

    对于第一组样例,两球在击球后4.0秒时发生碰撞,

    对于第二组样例,两球不发生碰撞,且在击球后5.5秒时两球距离最近,此时距离为2.0。

    Source

    Author

    quailty
    解:

    设时间为t时两个球相撞或者两个球距离最近,用t可以表示出两个球的坐标 Q1( x1+t*vx1  ,  y1+t*vy1)  Q2(  x2+t*vx2   ,    y2+t*vy2)  ,

    Q1Q2的距离=  aqrt{(x1-x2)^2  +(y1-y2)^2   } =r1+r2;     整理方程得到一个关于t 的一元二次方程  sqrt( a t^2  +  b t + c )=  r1+r2;

    求解该方程,分a=0和a!=0,a!=0,求解 △<0,△=0,△>0,当△<0时无解,求解方程左边的最小值 ,即 t = -b/(2*a),t>0, 带入方程得 d= sqrt ((4ac-b^2)/(4a) ),ans=d-(r1+r2);   t<0 ,ans=sqrt(c)-(r1+r2) 。 当△>=0时,ans=min(t1,t2)。当a=0,时,ans=sqrt(c)-(r1+r2)。

    又复习了一遍初中知识

    #include <iostream>
    #include <stdio.h>
    #include <math.h>
    #include <string.h>
    using namespace std;
    double solve(double a,double b,double c)
    {
        double dat=b*b-4.0*a*c;
        if(dat<0)
            return -1;
        double x1= ( -b+sqrt(dat) )/2.0/a;
        double x2= ( -b-sqrt(dat) )/2.0/a;
         if(x2>=0.0)
        return x2;
        if(x2<0&&x1>0)
            return x1;
        if(x1<0&&x2<0)
            return -1;
    }
    int main()
    {
        int t;
        double x1,y1,r1,vx1,vy1;
        double x2,y2,r2,vx2,vy2;
        double x,vx,y,vy;
        double a,b,c;
        double R;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%lf%lf%lf%lf%lf",&x1,&y1,&r1,&vx1,&vy1);
            scanf("%lf%lf%lf%lf%lf",&x2,&y2,&r2,&vx2,&vy2 );
            x=x1-x2;///c
            y=y1-y2;///c
            vx=vx1-vx2;///a
            vy=vy1-vy2;///a
    
            a=vx*vx+vy*vy;
            c=x*x+y*y;
            b=2.0*(x*vx+y*vy);
            R=1.0*(r1+r2)*(r1+r2);
            double t=-1.0*b/2.0/a;
            if(a!=0)
            {
                double ans=solve(a,b,c-R);
                if(ans<0&&t<0)
                printf("%.10lf\n",sqrt(c)-r1-r2);
    
                if(ans<0&&t>=0)
                printf("%.10lf\n",sqrt( (4.0*a*c-b*b) /(4.0*a) )-r1-r2);
    
                if(ans>=0)
                printf("%.10lf\n",ans);
            }
            else
            printf("%.10lf\n",sqrt(c)-r1-r2);
        }
        return 0;
    }
    


    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

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

    抵扣说明:

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

    余额充值