补完题后忙着补其他的了,就光把代码贴出来了,突然发现有人看,赶忙把题解发出来。
题意:求两条线段的最近距离。
题解:
首先求空间中两条异面直线的距离为d,求的方法是板子。。。
然后分两种情况:
一是,首先我们定义两条直线的距离的方向为v,也就是说,一条直线沿方向v平移,会与另一条直线相交。第一种情况就是,将线段沿方向v平移后交点在两条线段上,那么异面直线的距离就是两条线段的最短距离d。
二是,一中所说的交点不在两条线段上,那么最短距离就是以下4个距离的最小值。
线段1的两个端点到线段2的最短距离、线段2的两个端点到线段1的最短距离。
这里用到的模板就是点到线段的距离。
将距离用分数表示,手动模拟除法就行了。
现在的问题是,上面所说的交点在不在两条线段上,怎么判断呢?
设平面a为线段2与方向v的共平面,
那么如果A、B两点在平面a的同侧,说明交点不会在线段1上,同样的方法判断交点会不会在线段2上。
我的判断是否在平面同侧的方法是,求平面a的法向量n,判断向量CA与向量n的点积是否和向量CB与向量n的点积异号。
因为点积的正负表示向量夹角与的关系,如果A、B两点异侧,那么向量CA、CB与向量n的夹角一定是一个大于,一个小于。
求法向量用向量叉积即可。
这样所有问题就都解决了。
代码:
#include<bits/stdc++.h>
#define N 10010
#define LL long long
using namespace std;
struct Point
{
LL x,y,z;
Point(LL x=0,LL y=0,LL z=0):x(x),y(y),z(z){};
void read(){cin>>x>>y>>z;}
};
typedef Point Vector;
Vector operator + (Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y,a.z+b.z);}
Vector operator - (Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y,a.z-b.z);}
bool operator == (Vector a,Vector b){return a.x==b.x && a.y==b.y && a.z==b.z;}
LL Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y+a.z*b.z;} //点积
LL Length(Vector a){return Dot(a,a);}
Vector Cross(Vector a,Vector b) //叉积
{return Vector(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);}
LL z[5][2];
void spy(int x,Point p,Point a,Point b)
{
if(a==b)
{
z[x][0]=Length(p-a);z[x][1]=1;
return;
}
Vector v1=b-a,v2=p-a,v3=p-b;
if (Dot(v1,v2)<0) {z[x][0]=Length(v2);z[x][1]=1;}else
if (Dot(v1,v3)>0) {z[x][0]=Length(v3);z[x][1]=1;}else
{
z[x][0]=Length(Cross(v1,v2));z[x][1]=Length(v1);
}
}
void print(LL x,LL y)
{
int a[40];
cout<<x/y<<".";
LL t=x%y;
for (int i=0;i<30;i++)
{
t*=10;
a[i]=t/y;
t=t%y;
}
if(t*10/y>=5)a[29]++;
int i=29;
while(a[i]==10) {a[i]=0;a[--i]++;}
for (int i=0;i<30;i++)cout<<a[i];cout<<endl;
}
int main()
{
int T;
cin>>T;
Point a,b,aa,bb;
while(T--)
{
a.read();b.read();aa.read();bb.read();
Vector n=Cross(a-b,aa-bb);
Vector p1=Cross(b-a,n),p2=Cross(bb-aa,n);
if (Dot(aa-a,p1)*Dot(bb-a,p1)<0 && Dot(a-aa,p2)*Dot(b-aa,p2)<0)
{
Vector v=Cross(a-b,aa-bb);
if (Length(v)==0)
{
cout<<"0.000000000000000000000000000000"<<endl;
}else
{
LL ff=Dot(a-aa,v);
LL n=Length(v);
print(ff*ff,n);
}
}else
{
spy (1,a,aa,bb);
spy (2,b,aa,bb);
spy (3,aa,a,b);
spy (4,bb,a,b);
for (int i=2;i<=4;i++)
{
if (z[1][0]*z[i][1]>z[1][1]*z[i][0])
{
swap(z[1][0],z[i][0]);
swap(z[1][1],z[i][1]);
}
}
print(z[1][0],z[1][1]);
}
}
return 0;
}