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

题目链接

题目大意

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

题目思路

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

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

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

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 x=x0+vxty=y0+vytz=z0+vzt
可以推导出

( 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 (vx2h2+vy2h2r2vz2)t2+(2x0vxh2+2y0vyh2+2hvzr22z0vzr2)t+x02h2+y02h2r2h2r2z02+2hz0r2=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} a=vx2h2+vy2h2r2vz2b=2x0vxh2+2y0vyh2+2hvzr22z0vzr2c=x02h2+y02h2r2h2r2z02+2hz0r2x=2ab+b24ac

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值