您的位置:首页 > 其它

uvalive 4973

2015-07-31 21:26 253 查看
题意:给出空间两条线段,求他们的最近距离的平方,要用分数形式表示 : l / m两个互质数 其中m>0。

题解:有两种情况,如果两条线段平行或重合,直接计算线段每个端点到另一条线段的距离,取最小值。否则就是异面直线,模板函数带入进行了。。。因为一个变量名坑了一下午加一晚上。。。而且存数字要用long long。。。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

long long gcd(long long a, long long b) {
return b == 0 ? a : gcd(b, a % b);
}
long long lcm(long long a, long long b) {
return a / gcd(a, b) * b;
}
struct Rat {
long long a, b;
Rat(long long a = 0):a(a), b(1) {}
Rat(long long x, long long y):a(x), b(y) {
if (b < 0) {
a = -a;
b = -b;
}
long long temp = gcd(a, b);
if (temp < 0)
temp = -temp;
a /= temp;
b /= temp;
}
};
Rat operator + (const Rat& A, const Rat& B) {
long long temp = lcm(A.b, B.b);
return Rat(A.a * (temp / A.b) + B.a * (temp / B.b), temp);
}
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 Min(Rat& A, const Rat& B) {
if (A.a * B.b > B.a * A.b) {
A.a = B.a;
A.b = B.b;
}
}

struct Point3 {
long long x, y, z;
Point3(long long x = 0, long long y = 0, long long 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 Vector3& A, const Vector3& B) {
return Vector3(A.x - B.x, A.y - B.y, A.z - B.z);
}
Vector3 operator * (const Vector3& A, long long b) {
return Vector3(A.x * b, A.y * b, A.z * b);
}

bool operator == (const Point3& A, const Point3& B) {
return A.x == B.x && A.y == B.y && A.z == B.z;
}
long long Dot (const Vector3& A, const Vector3& B) {
return A.x * B.x + A.y * B.y + A.z * B.z;
}
long long Length(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);
}
//点到线段距离
Rat Rat_DistanceToSegment(const Point3& P, const Point3& A, const Point3& B) {
if (A == B)
return Rat(Length(P - A));
Vector3 v1 = B - A, v2 = P - A, v3 = P - B;
if (Dot(v1, v2) < 0)
return Rat(Length(v2));
if (Dot(v1, v3) > 0)
return Rat(Length(v3));
return Rat(Length(Cross(v1, v2)), Length(v1));
}
//求p1 + su和p2 + tv两个异面直线的公垂线,如果平行或重合返回false
//两次调用解出t和s两个参数
bool Rat_LineDistance3D(const Point3& p1, const Vector3& u, const Point3& p2, const Vector3& v, Rat& s) {
long long b = Dot(u, u) * Dot(v, v) - Dot(u, v) * Dot(u, v);
if (b == 0)
return false;
long long a = Dot(u, v) * Dot(v, p1 - p2) - 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;
}

int main() {
int cas;
scanf("%d", &cas);
while (cas--) {
Point3 L1[2], L2[2];
scanf("%lld%lld%lld%lld%lld%lld", &L1[0].x, &L1[0].y, &L1[0].z, &L1[1].x, &L1[1].y, &L1[1].z);
scanf("%lld%lld%lld%lld%lld%lld", &L2[0].x, &L2[0].y, &L2[0].z, &L2[1].x, &L2[1].y, &L2[1].z);
Rat res = Rat(1e9) s, t;
int flag = 0;
if (Rat_LineDistance3D(L1[0], L1[1] - L1[0], L2[0], L2[1] - L2[0], s)) {
if (s.a > 0 && s.a < s.b && Rat_LineDistance3D(L2[0], L2[1] - L2[0], L1[0], L1[1] - L1[0], t)) {
if (t.a > 0 && t.a < t.b) { //点要在线段上需要参数保证在0~1之间
flag = 1;
Rat x1, y1, z1, x2, y2, z2;
Rat_GetPointOnLine(L1[0], L1[1], s, x1, y1, z1);
Rat_GetPointOnLine(L2[0], L2[1], t, x2, y2, z2);
res = Rat((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) + (z1 - z2) * (z1 - z2));
}
}
}
if (!flag) {
Min(res, Rat_DistanceToSegment(L1[0], L2[0], L2[1]));
Min(res, Rat_DistanceToSegment(L1[1], L2[0], L2[1]));
Min(res, Rat_DistanceToSegment(L2[0], L1[0], L1[1]));
Min(res, Rat_DistanceToSegment(L2[1], L1[0], L1[1]));
}
if (res.a == 0)
res.b = 1;
printf("%lld %lld\n", res.a, res.b);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: