http://acm.hdu.edu.cn/showproblem.php?pid=6559
赛后一分钟过了,整场全员互演,队友改了我原来的代码我不知道,最后5分钟改问题的时候拿的不是原版代码改的。。
这题就列一个方程,首先z>=0,那么一定是在上面的面相交的,那么高度一定是0<=l<=h,那么交点的x,y坐标满足在半径为R=r/h*(h-l),所以有z0+vz*t=R,(x0+vxt)^2+(y0+vyt)^2=R^2,就是一个关于t的一元二次方程了
注意一元二次方程的特殊情况,如果a=0,说明点的速度向量与圆锥的母线平行,此时只有一个解,如果a=0且b=0,那么说明点原来的位置就在圆锥的母线上,那么此时这个方程就没了,直接用(z0-h)/(-vz)来算就好了,否则就会计算出两个解t1<=t2,如果t1<0,说明t1是与上方的圆锥母线的虚面相交了,所以此时取t1,注意t1,t2都大于0的时候还要判断一下,如果t1还是与虚面相交,就要取t2,t2时z坐标才会在[0,h]之间,否则如果是与圆锥的实面有两个交点,那么就取较小的那个。
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-10;
inline double mysqrt(double x)
{
return sqrt(max(0.0,x));
}
int main()
{
double r,h,x0,y0,z0,vx,vy,vz,ans,a,b,c,delta,t1,t2;
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
scanf("%lf%lf",&r,&h);
scanf("%lf%lf%lf",&x0,&y0,&z0);
scanf("%lf%lf%lf",&vx,&vy,&vz);
a=vx*vx+vy*vy-(r*r*vz*vz/h/h);
b=2*x0*vx+2*y0*vy-2*(r*r*z0*vz/h/h)+2*(r*r*vz/h);
c=x0*x0+y0*y0-(r*r*z0*z0/h/h)+2*(r*r*z0/h)-r*r;
if(a<-eps || a>eps)
{
delta=mysqrt(b*b-4*a*c);
t1=(-b-delta)/(2*a);
t2=(-b+delta)/(2*a);
if(t1>t2) swap(t1,t2);
if(t1<eps)
ans=t2;
else
{
if(z0+vz*t1>h)
ans=t2;
else
ans=t1;
}
}
else if(b>eps || b<-eps)
ans=-c/b;
else
ans=(z0-h)/(-vz);
printf("Case %d: %.10f\n",i,ans);
}
return 0;
}