题意:给出空间两条线段,求距离。
注意输出格式!
1 #include<cstdio> 2 #include<cmath> 3 #include<algorithm> 4 using namespace std; 5 6 struct Point3 7 { 8 int x, y, z; 9 Point3(int x=0, int y=0, int z=0):x(x),y(y),z(z) { } 10 }; 11 12 typedef Point3 Vector3; 13 14 Vector3 operator + (const Vector3& A, const Vector3& B) 15 { 16 return Vector3(A.x+B.x, A.y+B.y, A.z+B.z); 17 } 18 Vector3 operator - (const Point3& A, const Point3& B) 19 { 20 return Vector3(A.x-B.x, A.y-B.y, A.z-B.z); 21 } 22 Vector3 operator * (const Vector3& A, int p) 23 { 24 return Vector3(A.x*p, A.y*p, A.z*p); 25 } 26 27 bool operator == (const Point3& a, const Point3& b) 28 { 29 return a.x==b.x && a.y==b.y && a.z==b.z; 30 } 31 32 Point3 read_point3() 33 { 34 Point3 p; 35 scanf("%d%d%d", &p.x, &p.y, &p.z); 36 return p; 37 } 38 39 int Dot(const Vector3& A, const Vector3& B) 40 { 41 return A.x*B.x + A.y*B.y + A.z*B.z; 42 } 43 int Length2(const Vector3& A) 44 { 45 return Dot(A, A); 46 } 47 Vector3 Cross(const Vector3& A, const Vector3& B) 48 { 49 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); 50 } 51 52 typedef long long LL; 53 54 LL gcd(LL a, LL b) 55 { 56 return b ? gcd(b, a%b) : a; 57 } 58 LL lcm(LL a, LL b) 59 { 60 return a / gcd(a,b) * b; 61 } 62 63 struct Rat 64 { 65 LL a, b; 66 Rat(LL a=0):a(a),b(1) { } 67 Rat(LL x, LL y):a(x),b(y) 68 { 69 if(b < 0) a = -a, b = -b; 70 LL d = gcd(a, b); 71 if(d < 0) d = -d; 72 a /= d; 73 b /= d; 74 } 75 }; 76 77 Rat operator + (const Rat& A, const Rat& B) 78 { 79 LL x = lcm(A.b, B.b); 80 return Rat(A.a*(x/A.b)+B.a*(x/B.b), x); 81 } 82 83 Rat operator - (const Rat& A, const Rat& B) 84 { 85 return A + Rat(-B.a, B.b); 86 } 87 Rat operator * (const Rat& A, const Rat& B) 88 { 89 return Rat(A.a*B.a, A.b*B.b); 90 } 91 92 void updatemin(Rat& A, const Rat& B) 93 { 94 if(A.a*B.b > B.a*A.b) A.a = B.a, A.b = B.b; 95 } 96 97 // 点P到线段AB的距离的平方 98 Rat Rat_Distance2ToSegment(const Point3& P, const Point3& A, const Point3& B) 99 { 100 if(A == B) return Length2(P-A); 101 Vector3 v1 = B - A, v2 = P - A, v3 = P - B; 102 if(Dot(v1, v2) < 0) return Length2(v2); 103 else if(Dot(v1, v3) > 0) return Length2(v3); 104 else return Rat(Length2(Cross(v1, v2)), Length2(v1)); 105 } 106 107 // 求异面直线p1+su和p2+tv的公垂线对应的s。如果平行/重合,返回false 108 bool Rat_LineDistance3D(const Point3& p1, const Vector3& u, const Point3& p2, const Vector3& v, Rat& s) 109 { 110 LL b = (LL)Dot(u,u)*Dot(v,v) - (LL)Dot(u,v)*Dot(u,v); 111 if(b == 0) return false; 112 LL a = (LL)Dot(u,v)*Dot(v,p1-p2) - (LL)Dot(v,v)*Dot(u,p1-p2); 113 s = Rat(a, b); 114 return true; 115 } 116 117 void Rat_GetPointOnLine(const Point3& A, const Point3& B, const Rat& t, Rat& x, Rat& y, Rat& z) 118 { 119 x = Rat(A.x) + Rat(B.x-A.x) * t; 120 y = Rat(A.y) + Rat(B.y-A.y) * t; 121 z = Rat(A.z) + Rat(B.z-A.z) * t; 122 } 123 124 Rat Rat_Distance2(const Rat& x1, const Rat& y1, const Rat& z1, const Rat& x2, const Rat& y2, const Rat& z2) 125 { 126 return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2); 127 } 128 129 int main() 130 { 131 int T; 132 scanf("%d", &T); 133 LL maxx = 0; 134 while(T--) 135 { 136 Point3 A = read_point3(); 137 Point3 B = read_point3(); 138 Point3 C = read_point3(); 139 Point3 D = read_point3(); 140 Rat s, t; 141 bool ok = false; 142 Rat ans = Rat(1000000000); 143 if(Rat_LineDistance3D(A, B-A, C, D-C, s)) 144 if(s.a > 0 && s.a < s.b && Rat_LineDistance3D(C, D-C, A, B-A, t)) 145 if(t.a > 0 && t.a < t.b) 146 { 147 ok = true; // 异面直线/相交直线 148 Rat x1, y1, z1, x2, y2, z2; 149 Rat_GetPointOnLine(A, B, s, x1, y1, z1); 150 Rat_GetPointOnLine(C, D, t, x2, y2, z2); 151 ans = Rat_Distance2(x1, y1, z1, x2, y2, z2); 152 } 153 if(!ok) // 平行直线/重合直线 154 { 155 updatemin(ans, Rat_Distance2ToSegment(A, C, D)); 156 updatemin(ans, Rat_Distance2ToSegment(B, C, D)); 157 updatemin(ans, Rat_Distance2ToSegment(C, A, B)); 158 updatemin(ans, Rat_Distance2ToSegment(D, A, B)); 159 } 160 printf("%lld %lld\n", ans.a, ans.b); 161 } 162 return 0; 163 }
时间: 2024-10-09 06:29:11