题意:给若干无限长的圆柱,知道圆柱轴心上的一个点和同平面上的另外两个点,还有半径,判断是否有圆柱相交,不相交则输出最小距离。
思路:由于已知同平面上的三个点,其中一个点还是轴线上的点,所以可以确定出一个平面,然后求出法向量,法向量和轴心上的点就可以确定出轴心直线了。然后计算任意两条空间直线间的距离,由于只有30个圆柱,暴力嘛,用距离减去两圆柱的半径和,小于等于0则相交,大于0就不相交。空间直线的距离d=|AB*n| / |n| (AB表示异面直线任意2点的连线,n表示法向量,法向量为两条异面直线方向向量的叉积,|n|表示模。
#include<iostream> #include<vector> #include<queue> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; const int maxn=35; const double eps=1e-8; struct Point3 { double x,y,z; Point3(double x=0,double y=0,double z=0):x(x),y(y),z(z){} }a[maxn],b[maxn],c[maxn],v[maxn]; double r[maxn]; typedef Point3 Vector3; Vector3 operator + (Vector3 A,Vector3 B) { return Vector3(A.x+B.x,A.y+B.y,A.z+B.z); } Vector3 operator - (Vector3 A,Vector3 B) { return Vector3(A.x-B.x,A.y-B.y,A.z-B.z); } int dcmp(double x) { if(fabs(x)<eps) return 0; else return x<0?-1:1; } double Dot3(Vector3 A,Vector3 B) { return A.x*B.x+A.y*B.y+A.z*B.z; } double Length3(Vector3 A) { return sqrt(Dot3(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); } double dis(Point3 a,Point3 b,Vector3 v) { Vector3 p=a-b; return fabs(Dot3(p,v))/Length3(v); } int main() { int t,n; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i=0;i<n;i++) { scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf",&a[i].x,&a[i].y, &a[i].z,&b[i].x,&b[i].y,&b[i].z,&c[i].x,&c[i].y,&c[i].z); v[i]=Cross(b[i]-a[i],c[i]-a[i]); r[i]=Length3(b[i]-a[i]);
} int k=0; double ans,minm=1e9; for(int i=0;i<n;i++) { for(int j=i+1;j<n;j++) { Vector3 v1=Cross(v[i],v[j]); double ans=dis(a[i],a[j],v1)-r[i]-r[j]; if(ans<0 || dcmp(ans)==0) { k=1;break; } else { minm=min(ans,minm); } } if(k==1) break; } if(k==1) printf("Lucky\n"); else printf("%.2lf\n",minm); } return 0; }