吉林区域赛 E - The Tower 几何题

https://vjudge.net/contest/386991#problem/E

转自:https://blog.csdn.net/Du_Mingm/article/details/89791220

题意:给出一个底部圆圆心为(0,0,0),半径为r,高为h的圆锥,问起始位置为(x0,y0,z0),方向为(vx,vy,vz)的点撞上圆锥的时间。

有三角形相似,易知r'=\frac{r*(h-z)}{h}

然后带入对于r'所在平面带入圆的方程得

x^{2}+y^{2}=r'^{2}=\frac{r^{2}*(h-z)^{2}}{h^{2}}\ (z\in [0,h])

这就是圆锥面的方程了(底面是x^{2}+y^{2}<=r^{2}\ \ (z=0)

 

然后我们设所用时间为t

易知撞击点为<x+t*v_{x},y+t*v_{y},z+t*v_{z}>

 

然后把它带入圆锥面方程,得到关于t的一元二次方程,求解即可

 

相撞点也可能是在底面上(易知z=0,由此解出t),所以

撞击点也可能是<x+\frac{-z}{v_{z}}*v_{x},y+\frac{-z}{v_{z}}*v_{y},0>,这个点不一定在x^{2}+y^{2}<=r^{2}\ \ (z=0)内,所以要判断下

 

 

 

你以为这样结束了吗,并没有,还有两个小坑点

这时候最近的点并不是答案,所以也要判断一下(也就是交点的z范围在0到h之间)

 1 #include <bits/stdc++.h>
 2 typedef long long ll;
 3 using namespace std;
 4 const int maxn = 1e5+7;
 5 int T,Case;
 6 int main(){
 7     for(scanf("%d",&T);T--;){
 8         double h,r;
 9         double x,y,z,vx,vy,vz;
10         scanf("%lf%lf",&r,&h);
11         scanf("%lf%lf%lf",&x,&y,&z);
12         scanf("%lf%lf%lf",&vx,&vy,&vz);
13         double  a = (vx*vx*h*h+vy*vy*h*h-r*r*vz*vz),
14                 b = 2*(x*vx*h*h+y*vy*h*h+vz*h*r*r-vz*z*r*r),
15                 c = h*h*x*x+h*h*y*y+2*h*r*r*z-r*r*z*z-r*r*h*h;
16         double tans1 = (-b+sqrt(b*b-4*a*c))/(2*a);
17         double tans2 = (-b-sqrt(b*b-4*a*c))/(2*a);
18         double ans = 1e18;
19         if(tans1>0){
20             double tz = z+tans1*vz;
21             if(tz>=0&&tz<=h)
22                 ans = min(ans,tans1);
23         }
24         if(tans2>0){
25             double tz = z+tans2*vz;
26             if(tz>=0&&tz<=h)
27                 ans = min(ans,tans2);
28         }
29         //printf("%f \n%f\n",tans1,tans2);
30         if(fabs(vz)>1e-6){
31             double t = -z/vz;
32             double tx = x+t*vx,ty = y+t*vy;
33             if(tx*tx+ty*ty<=r*r)
34                 ans = min(ans,t);
35         }
36         printf("Case %d: %.10f\n",++Case,ans);
37     }
38     return 0;
39 }

 

posted @ 2020-09-28 09:18  古比  阅读(166)  评论(0编辑  收藏  举报