Doctor D. are researching for a horrific weapon. The muzzle of the weapon is a circle. When it fires, rays form a cylinder that runs through the circle verticality in both side. If one cylinder of rays touch another, there will be an horrific explosion. Originally, all circles can rotate easily. But for some unknown reasons they can not rotate any more. If these weapon can also make an explosion, then Doctor D. is lucky that he can also test the power of the weapon. If not, he would try to make an explosion by other means. One way is to find a medium to connect two cylinder. But he need to know the minimum length of medium he will prepare. When the medium connect the surface of the two cylinder, it may make an explosion.
Input The first line contains an integer T, indicating the number of testcases. For each testcase, the first line contains one integer N(1 < N < 30), the number of weapons. Each of the next 3N lines contains three float numbers. Every 3 lines represent one weapon. The first line represents the coordinates of center of the circle, and the second line and the third line represent two points in the circle which surrounds the center. It is supposed that these three points are not in one straight line. All float numbers are between -1000000 to 1000000. Output For each testcase, if there are two cylinder can touch each other, then output 'Lucky', otherwise output then minimum distance of any two cylinders, rounded to two decimals, where distance of two cylinders is the minimum distance of any two point in the surface of two cylinders. Sample Input
3 3 0 0 0 1 0 0 0 0 1 5 2 2 5 3 2 5 2 3 10 22 -2 11 22 -1 11 22 -3 3 0 0 0 1 0 1.5 1 0 -1.5 112 115 109 114 112 110 109 114 111 -110 -121 -130 -115 -129 -140 -104 -114 -119.801961 3 0 0 0 1 0 1.5 1 0 -1.5 112 115 109 114 112 110 109 114 111 -110 -121 -130 -120 -137 -150 -98 -107 -109.603922Sample Output
Lucky 2.32 Lucky
给你一些点的xyz坐标,每三个点是一组,表示一个平面圆上的圆心及圆上任意两点,(三点确定一个平面)
这个圆会发激光,无限长,问你空间中这么多点发的激光会不会重叠,只要重叠就输出“Lucky”,没有重叠的就输出激光之间最小的距离。
解题思路:
立体几何的知识,基本套模板,由于数据量不大(30),找的时候直接暴力,模板套好就万事大吉了。
用给出的三个点求出半径,模板求圆的法向量,然后用圆心这个点和圆心加上法向量的那个点构建空间直线(不要用原点和原点加法向量的那个点,因为空间中位置已经变化了,不再是确定的位置)
最后输出注意保留两位小数。
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <cmath> #include <iostream> using namespace std; const double EPS = 1e-9; const int MAXN = 40; struct Point3 //空间点 { double x, y, z; Point3( double x=0, double y=0, double z=0 ): x(x), y(y), z(z) { } Point3( const Point3& a ) { x = a.x; y = a.y; z = a.z; return; } void showP() { printf("%f %f %f \n", x, y, z); } Point3 operator+( Point3& rhs ) { return Point3( x+rhs.x, y+rhs.y, z+rhs.z ); } }f[35]; struct Line3 //空间直线 { Point3 a, b; }ff[35]; struct plane3 //空间平面 { Point3 a, b, c; double r; plane3() {} plane3( Point3 a, Point3 b, Point3 c ): a(a), b(b), c(c) { } void showPlane() { a.showP(); b.showP(); c.showP(); return; } }p[35]; double dcmp( double a ) { if ( fabs( a ) < EPS ) return 0; return a < 0 ? -1 : 1; } //三维叉积 Point3 Cross3( Point3 u, Point3 v ) { Point3 ret; ret.x = u.y * v.z - v.y * u.z; ret.y = u.z * v.x - u.x * v.z; ret.z = u.x * v.y - u.y * v.x; return ret; } //三维点积 double Dot3( Point3 u, Point3 v ) { return u.x * v.x + u.y * v.y + u.z * v.z; } //矢量差 Point3 Subt( Point3 u, Point3 v ) { Point3 ret; ret.x = u.x - v.x; ret.y = u.y - v.y; ret.z = u.z - v.z; return ret; } //两点距离 double TwoPointDistance( Point3 p1, Point3 p2 ) { return sqrt( (p1.x - p2.x)*(p1.x - p2.x) + (p1.y - p2.y)*(p1.y - p2.y) + (p1.z - p2.z)*(p1.z - p2.z) ); } //向量的模 double VectorLenth( Point3 p ) { return sqrt( p.x*p.x + p.y*p.y + p.z*p.z ); } double LineToLine( Line3 u, Line3 v ) { Point3 tmp = Cross3( Subt( u.a, u.b ), Subt( v.a, v.b ) ); return fabs( Dot3( Subt(u.a, v.a), tmp ) ) / VectorLenth(tmp); } //取平面法向量 Point3 pvec( plane3 s ) { return Cross3( Subt( s.a, s.b ), Subt( s.b, s.c ) ); } //空间平面与直线的交点 Point3 Intersection( Line3 l, plane3 s ) { Point3 ret = pvec(s); double t = ( ret.x*(s.a.x-l.a.x)+ret.y*(s.a.y-l.a.y)+ret.z*(s.a.z-l.a.z) )/( ret.x*(l.b.x-l.a.x)+ret.y*(l.b.y-l.a.y)+ret.z*(l.b.z-l.a.z) ); ret.x = l.a.x + ( l.b.x - l.a.x ) * t; ret.y = l.a.y + ( l.b.y - l.a.y ) * t; ret.z = l.a.z + ( l.b.z - l.a.z ) * t; return ret; } int main() { int t,n; cin>>t; while(t--) { scanf("%d",&n); memset(p,0,sizeof(p)); memset(f,0,sizeof(f)); memset(ff,0,sizeof(ff)); for(int i=0;i<n;i++) { cin>>p[i].a.x>>p[i].a.y>>p[i].a.z; cin>>p[i].b.x>>p[i].b.y>>p[i].b.z; cin>>p[i].c.x>>p[i].c.y>>p[i].c.z; f[i]=pvec(p[i]); ff[i].a.x=p[i].a.x;ff[i].a.y=p[i].a.y;ff[i].a.z=p[i].a.z;//圆心 ff[i].b=ff[i].a+f[i];//圆心加法向量 p[i].r=TwoPointDistance(p[i].a,p[i].b); //cout<<" p "<<i<<" r= "<<p[i].r<<endl; } double min=LineToLine(ff[0],ff[1]); if(min<=0) { cout<<"Lucky"<<endl;continue; } for(int i=0;i<n;i++) {for(int j=i+1;j<n;j++) { if(LineToLine(ff[i],ff[j])-p[i].r-p[j].r<min) min=LineToLine(ff[i],ff[j])-p[i].r-p[j].r; if(min<=0) { cout<<"Lucky"<<endl;break; } }if(min<=0)break; } if(min>0) printf("%.2lf\n",min); } return 0; }