HDU 4617 Weapon (计算几何:异面直线距离)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4617

 

题意:给出空间内的n个圆的圆心及圆上两点,即n个无限延长的光柱的截面,问这些圆柱是否会交在一起,如果不交输出最短距离,否则输出"Lucky"

 

思路:对于每个圆,找出其法向量直线,这样每两条法向量直线的间距减去两圆的半径和即是距离,判断该距离是否<=0即可

 

 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <utility>
#include <functional>
#include <vector>
#include <queue>
#include <string>
#include <set>
#include <map>
#pragma comment (linker, "/STACK:1024000000,1024000000")

#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define eps 1e-8
#define sign(x) ((x) > eps ? 1 : ((x) < -eps ? (-1) : (0)))

using namespace std;

typedef long long ll;

int n;

struct point
{
    double x, y, z;
    point() {}
    point(double _x, double _y, double _z)
    {
        x = _x;
        y = _y;
        z = _z;
    }
    void input()
    {
        scanf("%lf%lf%lf", &x, &y, &z);
    }
    point operator + (const point &b) const
    {
        return point(x + b.x, y + b.y, z + b.z);
    }
};

struct line
{
    point a, b;
};

struct circle
{
    point o, p1, p2;

    void input()
    {
        o.input();
        p1.input();
        p2.input();
    }
} c[100];

point xmult(point u, point v)
{
    point ret;
    ret.x = u.y * v.z - v.y * u.z;
    ret.y = u.z * v.x - u.x * v.z;
    ret.z = u.x * v.y - u.y * v.x;
    return ret;
}

double dis(point u, point v)
{
    return sqrt((u.x - v.x) * (u.x - v.x) + (u.y - v.y) * (u.y - v.y) + (u.z - v.z) * (u.z - v.z));
}

double dmult(point u, point v)
{
    return u.x * v.x + u.y * v.y + u.z * v.z;
}

point sub(point u, point v)
{
    point ret;
    ret.x = u.x - v.x;
    ret.y = u.y - v.y;
    ret.z = u.z - v.z;
    return ret;
}

double vlen(point p)
{
    return sqrt(p.x * p.x + p.y * p.y + p.z * p.z);
}

point pvec(circle s)
{
    return xmult(sub(s.o, s.p1), sub(s.p1, s.p2));
}

double linedis(line u, line v)
{
    point n = xmult(sub(u.a, u.b), sub(v.a, v.b));
    return fabs(dmult(sub(u.a, v.a), n)) / vlen(n);
}

void solve()
{
    double ans = 1e9;
    for(int i = 0; i < n; i++)
    {
        for(int j = i + 1; j < n; j++)
        {
            circle c1 = c[i], c2 = c[j];
            double r1 = dis(c[i].o, c[i].p1);
            double r2 = dis(c[j].o, c[j].p1);

            point k1 = pvec(c1);
            point k2 = pvec(c2);

            line l1, l2;
            l1.a = c1.o, l1.b = k1 + c1.o;
            l2.a = c2.o, l2.b = k2 + c2.o;

            double d = linedis(l1, l2);
            if(sign(d - r1 - r2) <= 0)
            {
                puts("Lucky");
                return ;
            }
            ans = min(ans, d - r1 - r2);
        }
    }
    printf("%.2f\n", ans);
}

int main()
{
    int t;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
            c[i].input();
        solve();
    }
    return 0;
}

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值