HDU 6559 The Tower 题解(计算几何)

题目链接

题目大意

给出一个底部圆圆心为(0,0,0),半径为r,高为h的圆锥,问起始位置为 x 0 y 0 z 0 (x_0,y_0,z_0) ,方向为 v x , v y , v z (v_x,v_y,v_z) 的点撞上圆锥的时间。

题目思路

想了一段时间都没什么思路,其实就是很普通的一个解方程。。。

假设碰撞点的坐标为(x,y,z)那么根据相似三角形

x 2 + y 2 r = h z h \frac{\sqrt{x^2+y^2}}{r}=\frac{h-z}{h} 然后根据

x = x 0 + v x t y = y 0 + v y t z = z 0 + v z t x=x_0+v_x*t \\y=y_0+v_y*t\\ z=z_0+v_z*t
可以推导出

( v x 2 h 2 + v y 2 h 2 r 2 v z 2 ) t 2 + ( 2 x 0 v x h 2 + 2 y 0 v y h 2 + 2 h v z r 2 2 z 0 v z r 2 ) t + x 0 2 h 2 + y 0 2 h 2 r 2 h 2 r 2 z 0 2 + 2 h z 0 r 2 = 0 (v_x^2h^2+v_y^2h^2-r^2v_z^2)*t^2+(2x_0v_xh^2+2y_0v_yh^2+2hv_zr^2-2z_0v_zr^2)*t+x_0^2h^2+y_0^2h^2-r^2h^2-r^2z_0^2+2hz_0r^2=0

然后不就是解一个二元一次方程吗

a = v x 2 h 2 + v y 2 h 2 r 2 v z 2 b = 2 x 0 v x h 2 + 2 y 0 v y h 2 + 2 h v z r 2 2 z 0 v z r 2 c = x 0 2 h 2 + y 0 2 h 2 r 2 h 2 r 2 z 0 2 + 2 h z 0 r 2 x = b + b 2 4 a c 2 a a=v_x^2h^2+v_y^2h^2-r^2v_z^2\\b=2x_0v_xh^2+2y_0v_yh^2+2hv_zr^2-2z_0v_zr^2\\c=x_0^2h^2+y_0^2h^2-r^2h^2-r^2z_0^2+2hz_0r^2\\x=\frac{-b\frac{+}{}\sqrt{b^2-4ac}}{2a}

要注意的是,我们写出的圆锥方程是 z [ 0 , h ] z∈[0,h] 的,而在程序中没有表示所以是上下两个圆锥底对底拼在一起的,因此我们得到两个撞击点。因为保证了撞击点是存在的,所以我们只需要判断, t 1 t_1 时的撞击点是否满足 t 1 > 0 t_1>0 0 < = z 0 + v z t 1 < = h 0<=z_0+v_z*t_1<=h

代码

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#define fi first
#define se second
#define debug printf(" I am here\n");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e5+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-10;
int tot;
double r,h,x0,y0,z0,vx,vy,vz;
signed main(){
    int _;scanf("%d",&_);
    while(_--){
        scanf("%lf%lf",&r,&h);
        scanf("%lf%lf%lf",&x0,&y0,&z0);
        scanf("%lf%lf%lf",&vx,&vy,&vz);
        double a=vx*vx*h*h+vy*vy*h*h-r*r*vz*vz;
        double b=2*x0*vx*h*h+2*y0*vy*h*h+2*h*vz*r*r-2*z0*vz*r*r;
        double c=x0*x0*h*h+y0*y0*h*h-r*r*h*h-r*r*z0*z0+2*h*z0*r*r;
        double t1=(-b-sqrt(b*b-4*a*c))/(2*a);
        double t2=(-b+sqrt(b*b-4*a*c))/(2*a);
        if(t1>t2) swap(t1,t2);
        if(t1<0){
            printf("Case %d: %.10f\n",++tot,t2);
        }else{
            if(0<=z0+vz*t1&&z0+vz*t1<=h){
                printf("Case %d: %.10f\n",++tot,t1);
            }else{
                printf("Case %d: %.10f\n",++tot,t2);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_46209312/article/details/107861954