题目地址: 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;
}