2018 icpc Regional Dhaka I Triangles
题意:给你三维空间上的两个三角形,问两个三角形中最近的两个点的距离。
分析:首先,我们可以肯定最近的点对中的某一个一定出现在六条边上。而且可以肯定每一条边上的边的点距离另一个三角形是一个单峰函数,所以我们可以三分这个点。
接下来,我们要得到一个点到另一个三角形的距离。这里有一个讨论,如果这个点投影到另一个三角形所在平面在三角形内,我们直接求投影,否则求点到线段距离。
点到线段距离同理,如果点到线段投影在线段内部,可以直接求出投影距离,否则求出到端点距离。
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-9;
const double inf = 1e9;
int n;
struct V{
double x, y, z;
V(){}
V(double _x, double _y, double _z){
x=_x;
y=_y;
z=_z;
}
};
V operator+(const V& a, const V& b){
return {a.x+b.x,a.y+b.y,a.z+b.z};
}
V operator-(const V& a, const V& b){
return {a.x-b.x,a.y-b.y,a.z-b.z};
}
V operator*(const V& a, const double l){
return {a.x*l,a.y*l,a.z*l};
}
V operator/(const V& a, const double l){
return {a.x/l,a.y/l,a.z/l};
}
double dot(const V& a, const V& b){
return a.x*b.x+a.y*b.y+a.z*b.z;
}
V det(const V& a, const V& b){
return {
a.y*b.z-a.z*b.y,
a.z*b.x-a.x*b.z,
a.x*b.y-a.y*b.x,
};
}
V A[4], B[4];
double norm(const V& a){
return sqrt(dot(a,a));
}
inline void chmin(double& x, double y){
if(y<x)x=y;
}
double p2seg(V a, V b, V c){
double res=min(norm(a-b),norm(a-c));
if(dot(a-b,c-b)<0){
return res;
}
if(dot(a-c,b-c)<0){
return res;
}
return min(res,norm(det(a-b,c-b)/norm(b-c)));
}
double calc(V a, V b, V c, V d){
double res=min({p2seg(a,b,c),p2seg(a,c,d),p2seg(a,b,d)});
V t=det(c-b,d-b);
t=t/norm(t);
double dis=dot(t,a-b);
a=a-t*dis;
if(dot(det(d-c,a-c),det(b-c,a-c))>0){
return res;
}
if(dot(det(c-b,a-b),det(d-b,a-b))>0){
return res;
}
if(dot(det(b-d,a-d),det(c-d,a-d))>0){
return res;
}
return min(res,fabs(dis));
}
double solve(V a, V b, V d, V e, V f){
V v=b-a;
double l=0.0, r=1.0;
int _=100;
while(_--){
double tl=l+(r-l)/3;
double tr=r-(r-l)/3;
double len1=calc(a+v*tl,d,e,f);
double len2=calc(a+v*tr,d,e,f);
if(len1<len2){
r=tr;
}else{
l=tl;
}
}
double mid=(l+r)/2.0;
return calc(a+v*mid,d,e,f);
}
int main(){
ios_base::sync_with_stdio(0);
cin.tie(0);
int _;cin>>_;
while(_--){
for(int i=1;i<=3;++i){
cin>>A[i].x>>A[i].y>>A[i].z;
}
for(int i=1;i<=3;++i){
cin>>B[i].x>>B[i].y>>B[i].z;
}
double res=inf;
for(int i=1;i<=3;++i){
for(int j=i+1;j<=3;++j){
chmin(res,solve(A[i],A[j],B[1],B[2],B[3]));
}
}
for(int i=1;i<=3;++i){
for(int j=i+1;j<=3;++j){
chmin(res,solve(B[i],B[j],A[1],A[2],A[3]));
}
}
printf("%.6f\n",res);
}
return 0;
}