LA 4973 Ardenia 空间中线段的距离 要求用有理数输出

题目地址:LA49731  需要zi'ji
摘要由CSDN通过智能技术生成

题目地址: LA4973

1  需要自己编写有理数类

2  为了比较大小 应该把分母化为正数  

3  ==最好不是分子=分子 分母=分母  0是个bug  ==0 应该是rat.b==0  

4 wa了几个小时的地方...分数相加要用lcm通分.. 不然wa 应该是爆long long了  

#include<iostream>
#include<cmath>
#include<cstdio>

//#include<cstdlib>


using namespace std;

typedef  long  long  LL;

LL gcd(LL a,LL b)
{
    if(b==0) return a;
    else return gcd(b,a%b);
    
}
LL lcm(LL a,LL b)
{
    return  a/gcd(a,b)*b;
    
}
 //定义有理数类
struct  Rat
{
    LL a,b;
    Rat(LL a=0):a(a),b(1){
     }
    
    
    Rat(LL aa,LL bb){
    
        LL d=gcd(aa,bb);
        aa/=d;
        bb/=d;
        
    if(bb<0)
    {
        aa=-aa;
        bb=-bb;
    }
        
        this->a=aa;
        this->b=bb;
        
    }
   

};



void  simplify(Rat & A)
{
    LL & a=A.a;
    LL & b=A.b;
    
    LL thegcd=gcd(a,b);
    a/=thegcd;
    b/=thegcd;
    
    if(b<0)
    {
        a=-a;
        b=-b;
    }
    
}


//Rat operator+(Rat A,Rat B)
//{
//    LL a=A.a*B.b+B.a*A.b;
//    LL b=A.b*B.b;
//
//    
//    return Rat(a,b);
//    
//}
//
//Rat operator-(Rat A,Rat B)
//{
//    LL a=A.a*B.b-B.a*A.b;
//    LL b=A.b*B.b;
//    
//    
//    return Rat(a,b);
//  
//}


Rat operator + (const Rat& A, const Rat& B) {
    LL x = lcm(A.b, B.b);
    return Rat(A.a*(x/A.b)+B.a*(x/B.b), x);
}

Rat operator - (const Rat& A, const Rat& B) { return A + Rat(-B.a, B.b); }

Rat operator*(Rat A,Rat B)
{
    LL a=A.a*B.a;
    LL b=A.b*B.b;
    
    
    return Rat(a,b);
    
}

Rat operator/(Rat A,Rat B)
{
    LL a=A.a*B.b;
    LL b=A.b*B.a;
    
    return Rat(a,b);
    
}


bool operator==(Rat A,Rat B)
{
    return A.a*B.b==A.b*B.a;
    
}

bool operator<(Rat A,Rat B)
{
    return A.a*B.b<B.a*A.b;
    
}

Rat abs(Rat x)
{
    return  Rat(abs(x.a),abs(x.b));
    
}

Rat zero(0,1);



struct Point3
{
    Rat x,y,z;
    Point3(Rat x=zero,Rat y=zero,Rat z=zero):x(x),y(y),z(z) {}
    
};

typedef Point3 Vector3;

Vector3 operator+(Point3 A,Point3 B)
{
    return Point3(A.x+B.x,A.y+B.y,A.z+B.z);
    
}

Vector3 operator-(Point3 A,Point3 B)
{
    return Point3(A.x-B.x,A.y-B.y,A.z-B.z);
    
}

Vector3 operator*(Point3 A,Rat p)
{
    return Point3(A.x*p,A.y*p,A.z*p);
    
}

Vector3 operator/(Point3 A,Rat p)
{
    return Point3(A.x/p,A.y/p,A.z/p);
    
}

bool operator<(Point3 &A,Point3 &B)
{
    return A.x<B.x||(A.x==B.x&&A.y<B.y)||(A.x==B.x&&A.y==B.y&&A.z<B.z);
    
}
bool operator==(Point3 &A,Point3 &B)
{
    return A.x==B.x&&A.y==B.y&&A.z==B.z;
}


Rat Dot(Vector3 A,Vector3 B)
{
    return  A.x*B.x+A.y*B.y+A.z*B.z;
}

Rat Length2(Vector3 A)
{
    return Dot(A,A);
}




Vector3 Cross(Vector3 A,Vector3 B)   // 真正的叉积
{
    return  Vector3(A.y*B.z-A.z*B.y,A.z*B.x-A.x*B.z,A.x*B.y-A.y*B.x);
}


// 距离的平方
Rat Distance2ToLine(Point3 P,Point3 A,Point3 B)
{
    Vector3 v1=B-A;
    Vector3 v2=P-A;
    return  Length2(Cross(v1, v2))/Length2(v1);
    
}


Rat  DistanceToSegment(Point3 P,Point3 A,Point3 B)
{
    if(A==B)      {
        
        
        return

        Length2(P-A);
        
    }
    
    Vector3 v1=B-A,v2=P-A,v3=P-B;
    if(Dot(v1,v2)<zero)
    {
      
         return Length2(v2);
    }
    
    else if(zero<Dot(v1,v3))
    {

      return Length2(v3);
    }
    
    else
    {
       return Length2(Cross(v1,v2))/Length2(v1);
    }
    
}





//  异面直线距离 求第一个的系数


bool LineDistance3D(Point3 p1,Vector3  u,Point3 p2,Vector3 v,Rat &s)
{
    Rat b=Dot(u,u)*Dot(v,v)-Dot(u,v)*Dot(u,v);
    if(b.a==0) return false;
    
    Rat a=Dot(u,v)*Dot(v,p1-p2)-Dot(v,v)*Dot(u,p1-p2);
    s=a/b;
    return true;
    
}

Rat SegToSeg3D(Point3 A,Point3 B,Point3 C,Point3 D)
{
   
    bool ok=0;
    Rat s,t,ans=Rat(1000000000);
    
    if(LineDistance3D(A, B-A, C, D-C, s)&&s.a>0&&s.a<s.b&&LineDistance3D(C, D-C, A, B-A, t)&&t.a>0&&t.a<t.b)
    {
        Point3  P=A+(B-A)*s;
        Point3  Q=C+(D-C)*t;
        Rat  dist=Length2(P-Q);
        ok=1;
        ans=dist;
    }
    
    if(!ok)
    {
        Rat d[4];
        
        d[0]=DistanceToSegment(A, C, D);
        d[1]=DistanceToSegment(B, C, D);
        d[2]=DistanceToSegment(C, A, B);
        d[3]=DistanceToSegment(D, A, B);
        
        for(int i=0;i<4;i++)
        {
            
            if(d[i]<ans)  ans=d[i];
            
        }
        
    }
    return ans;
}


Point3 read_point3()
{
    LL x,y,z;
    scanf("%lld%lld%lld",&x,&y,&z);
    Rat r_x=Rat(x,1);
    Rat r_y=Rat(y,1);
    Rat r_z=Rat(z,1);
    
    return  Point3(r_x,r_y,r_z);
    
}


int main()
{
    int T;
    cin>>T;
    Point3 A,B,C,D;
    while(T--)
    {
        A=read_point3();
        B=read_point3();
        C=read_point3();
        D=read_point3();
        
        Rat ans=SegToSeg3D(A,B,C,D);
        simplify(ans);
        
        printf("%lld %lld\n", ans.a, ans.b);
        
    }
    return 0;
}

/*
      13
         -20 -20 -20 20 20 19
        0 0 0 1 1 1
 
       -20 -20 -20 20 19 20
       -20 -20 20 20 20 -20
 
       0 0 0 20 20 20
       0 0 10 0 20 10
 
       0 0 0 1 1 1
       2 3 4 1 2 2
 
       0 0 0 0 0 0
       0 1 1 1 2 3
 
      0 0 0 10 10 10
      11 12 13 10 11 11
 
      0 0 0 1 1 1
      1 1 1 2 2 2
 
      1 0 0 0 1 0
      1 1 0 2 2 0
 
      1 0 0 0 1 0
      0 0 0 1 1 0
 
      0 0 0 0 0 20
      20 0 10 0 20 10
 
      0 0 0 20 20 20
      1 1 2 1 1 2
 
      0 0 0 20 20 20
      0 20 20 0 20 20
 
       0 0 0 0 0 20
      20 20 0 20 20 20
 
 
 */

 


运行速度是比较慢的,因为大量的有理数运算

LRJ的版本运行很快

// LA4973 Ardenia
// Rujia Liu
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;

struct Point3 {
    int x, y, z;
    Point3(int x=0, int y=0, int z=0):x(x),y(y),z(z) { }
};

typedef Point3 Vector3;

Vector3 operator + (const Vector3& A, const Vector3& B) { return Vector3(A.x+B.x, A.y+B.y, A.z+B.z); }
Vector3 operator - (const Point3& A, const Point3& B) { return Vector3(A.x-B.x, A.y-B.y, A.z-B.z); }
Vector3 operator * (const Vector3& A, int p) { return Vector3(A.x*p, A.y*p, A.z*p); }

bool operator == (const Point3& a, const Point3& b) {
    return a.x==b.x && a.y==b.y && a.z==b.z;
}

Point3 read_point3() {
    Point3 p;
    scanf("%d%d%d", &p.x, &p.y, &p.z);
    return p;
}

int Dot(const Vector3& A, const Vector3& B) { return A.x*B.x + A.y*B.y + A.z*B.z; }
int Length2(const Vector3& A) { return Dot(A, A); }
Vector3 Cross(const Vector3& A, const Vector3& B) { return Vector3(A.y*B.z - A.z*B.y, A.z*B.x - A.x*B.z, A.x*B.y - A.y*B.x); }

typedef long long LL;

LL gcd(LL a, LL b) { return b ? gcd(b, a%b) : a; }
LL lcm(LL a, LL b) { return a / gcd(a,b) * b; }

struct Rat {
    LL a, b;
    Rat(LL a=0):a(a),b(1) { }
    Rat(LL x, LL y):a(x),b(y) {
        if(b < 0) a = -a, b = -b;
        LL d = gcd(a, b); if(d < 0) d = -d;
        a /= d; b /= d;
    }
};

Rat operator + (const Rat& A, const Rat& B) {
    LL x = lcm(A.b, B.b);
    return Rat(A.a*(x/A.b)+B.a*(x/B.b), x);
}

Rat operator - (const Rat& A, const Rat& B) { return A + Rat(-B.a, B.b); }
Rat operator * (const Rat& A, const Rat& B) { return Rat(A.a*B.a, A.b*B.b); }

void updatemin(Rat& A, const Rat& B) {
    if(A.a*B.b > B.a*A.b) A.a = B.a, A.b = B.b;
}

// 点P到线段AB的距离的平方
Rat Rat_Distance2ToSegment(const Point3& P, const Point3& A, const Point3& B) {
    if(A == B) return Length2(P-A);
    Vector3 v1 = B - A, v2 = P - A, v3 = P - B;
    if(Dot(v1, v2) < 0) return Length2(v2);
    else if(Dot(v1, v3) > 0) return Length2(v3);
    else return Rat(Length2(Cross(v1, v2)), Length2(v1));
}

// 求异面直线p1+su和p2+tv的公垂线对应的s。如果平行/重合,返回false
bool Rat_LineDistance3D(const Point3& p1, const Vector3& u, const Point3& p2, const Vector3& v, Rat& s) {
    LL b = (LL)Dot(u,u)*Dot(v,v) - (LL)Dot(u,v)*Dot(u,v);
    if(b == 0) return false;
    LL a = (LL)Dot(u,v)*Dot(v,p1-p2) - (LL)Dot(v,v)*Dot(u,p1-p2);
    s = Rat(a, b);
    return true;
}

void Rat_GetPointOnLine(const Point3& A, const Point3& B, const Rat& t, Rat& x, Rat& y, Rat& z) {
    x = Rat(A.x) + Rat(B.x-A.x) * t;
    y = Rat(A.y) + Rat(B.y-A.y) * t;
    z = Rat(A.z) + Rat(B.z-A.z) * t;
}

Rat Rat_Distance2(const Rat& x1, const Rat& y1, const Rat& z1, const Rat& x2, const Rat& y2, const Rat& z2) {
    return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2);
}

int main() {
    int T;
    scanf("%d", &T);
    LL maxx = 0;
    while(T--) {
        Point3 A = read_point3();
        Point3 B = read_point3();
        Point3 C = read_point3();
        Point3 D = read_point3();
        Rat s, t;
        bool ok = false;
        Rat ans = Rat(1000000000);
        if(Rat_LineDistance3D(A, B-A, C, D-C, s))
            if(s.a > 0 && s.a < s.b && Rat_LineDistance3D(C, D-C, A, B-A, t))
                if(t.a > 0 && t.a < t.b) {
                    ok = true; // 异面直线/相交直线
                    Rat x1, y1, z1, x2, y2, z2;
                    Rat_GetPointOnLine(A, B, s, x1, y1, z1);
                    Rat_GetPointOnLine(C, D, t, x2, y2, z2);
                    ans = Rat_Distance2(x1, y1, z1, x2, y2, z2);
                }
        if(!ok) { // 平行直线/重合直线
            updatemin(ans, Rat_Distance2ToSegment(A, C, D));
            updatemin(ans, Rat_Distance2ToSegment(B, C, D));
            updatemin(ans, Rat_Distance2ToSegment(C, A, B));
            updatemin(ans, Rat_Distance2ToSegment(D, A, B));
        }
        printf("%lld %lld\n", ans.a, ans.b);
    }
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值