HDU 4741 Save Labman No.004

题意:有两条异面直线,在这两条直线上分别各找一点,使得这两点间的距离最短
P1 是直线L1上的点, S1 是直线 L1 的方向向量
P2 是直线 L2 上的点, S2 是直线 L2 的方向向量
这样 S1×S2 L1 L2 的公垂线
不妨设 P1+t1S1 P2+t2S2 是满足题意的一对点,则

P1+t1S1=P2+t2S2+t(S1×S2)

移项得
t1S1=(P2P1)+t2S2+t(S1×S2)

为消 t2 ,左右都叉乘 S2
t1(S1×S2)=(P2P1)×S2+t((S1×S2)×S2)

为了把t1的系数变成数左右都点乘S1×S2得
t1|S1×S2|2=((P2P1)×S2)(S1×S2)

化简得
t1=((P2P1)×S2)(S1×S2)|S1×S2|2

同理
t2=((P1P2)×S1)(S2×S1)|S2×S1|2

这样点就求出来了

#include <cstdio>
#include <math.h>

struct P
{
    double x, y, z;
    P(){}
    P(double _x, double _y, double _z){x = _x; y = _y; z = _z;}
}p1, p3, p2, p4, s1, s2;
P operator + (P a, P b) {return P(a.x + b.x, a.y + b.y, a.z + b.z);}
P operator - (P a, P b) {return P(a.x - b.x, a.y - b.y, a.z - b.z);}
P operator * (double t, P a) {return P(t * a.x, t * a.y, t * a.z);}
double dot(P a, P b) {return a.x * b.x + a.y * b.y + a.z * b.z;}
P cross(P a, P b) {return P(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);}

int main()
{
    int T;
    scanf("%d", &T);

    while(T--)
    {
        scanf("%lf%lf%lf", &p1.x, &p1.y, &p1.z);
        scanf("%lf%lf%lf", &p3.x, &p3.y, &p3.z);
        scanf("%lf%lf%lf", &p2.x, &p2.y, &p2.z);
        scanf("%lf%lf%lf", &p4.x, &p4.y, &p4.z);
        s1 = p3 - p1; s2 = p4 - p2;
        double t1 = dot(cross(p2 - p1, s2), cross(s1, s2))/dot(cross(s1,s2), cross(s1,s2));
        double t2 = dot(cross(p1 - p2, s1), cross(s2, s1))/dot(cross(s2,s1), cross(s2,s1));
        P a = p1 + t1 * s1;
        P b = p2 + t2 * s2;

        printf("%.6f\n", sqrt(dot(a - b, a - b)));
        printf("%.6f %.6f %.6f ", a.x, a.y, a.z);
        printf("%.6f %.6f %.6f\n", b.x, b.y, b.z);
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值