题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4266
题意:求三维凸包内一点到凸包表面最小距离。
思路:模板。
struct Point
{
double x,y,z;
Point() {}
Point(double _x,double _y,double _z)
{
x=_x;
y=_y;
z=_z;
}
void Get()
{
RD(x,y,z);
}
Point operator-(const Point p1)
{
return Point(x-p1.x,y-p1.y,z-p1.z);
}
Point operator*(Point p)
{
return Point(y*p.z-z*p.y,z*p.x-x*p.z,x*p.y-y*p.x);
}
double operator^(Point p)
{
return x*p.x+y*p.y+z*p.z;
}
double len()
{
return sqrt(sqr(x)+sqr(y)+sqr(z));
}
};
struct _3DCH
{
struct face
{
int a,b,c,ok;
face(){}
face(int _a,int _b,int _c,int _ok)
{
a=_a;
b=_b;
c=_c;
ok=_ok;
}
}F[N<<2];
int n,cnt,b[N][N];
Point p[N];
int DB(double x)
{
if(x>1e-10) return 1;
if(x<-1e-10) return -1;
return 0;
}
double vlen(Point a)
{
return a.len();
}
double getArea(Point a,Point b,Point c)
{
return vlen((b-a)*(c-a));
}
double getVolume(Point a,Point b,Point c,Point d)
{
return (b-a)*(c-a)^(d-a);
}
//t在f的正面返回1,反面返回-1,在f上返回0
int getDir(Point t,face f)
{
double x=(p[f.b]-p[f.a])*(p[f.c]-p[f.a])^(t-p[f.a]);
return DB(x);
}
void deal(int i,int x,int y)
{
int f=b[x][y];
face temp;
if(!F[f].ok) return;
if(getDir(p[i],F[f])>0) DFS(i,f);
else
{
temp=face(y,x,i,1);
b[y][x]=b[x][i]=b[i][y]=cnt;
F[cnt++]=temp;
}
}
void DFS(int i,int j)
{
F[j].ok=0;
deal(i,F[j].b,F[j].a);
deal(i,F[j].c,F[j].b);
deal(i,F[j].a,F[j].c);
}
void construct()
{
if(n<4) return;
int i,j,k=0;
FOR1(i,n-1) if(DB(vlen(p[0]-p[i])))
{
swap(p[1],p[i]);
k=1;
break;
}
if(!k) return;
k=0;
FOR(i,2,n-1) if(DB(getArea(p[0],p[1],p[i])))
{
swap(p[2],p[i]);
k=1;
break;
}
if(!k) return;;
k=0;
FOR(i,3,n-1) if(DB(getVolume(p[0],p[1],p[2],p[i])))
{
swap(p[3],p[i]);
k=1;
break;
}
if(!k) return;
cnt=0;
face temp;
FOR0(i,4)
{
temp=face((i+1)%4,(i+2)%4,(i+3)%4,1);
if(getDir(p[i],temp)>0) swap(temp.b,temp.c);
b[temp.a][temp.b]=b[temp.b][temp.c]=b[temp.c][temp.a]=cnt;
F[cnt++]=temp;
}
FOR(i,4,n-1) FOR0(j,cnt) if(F[j].ok&&getDir(p[i],F[j])>0)
{
DFS(i,j);
break;
}
j=0;
FOR0(i,cnt) if(F[i].ok) F[j++]=F[i];
cnt=j;
}
double getSumArea()
{
double ans=0;
int i;
FOR0(i,cnt) ans+=getArea(p[F[i].a],p[F[i].b],p[F[i].c]);
return ans/2;
}
int isSame(face a,face b)
{
Point x1=p[a.a],y1=p[a.b],z1=p[a.c];
Point x2=p[b.a],y2=p[b.b],z2=p[b.c];
if(DB(getVolume(x1,y1,z1,x2))) return 0;
if(DB(getVolume(x1,y1,z1,y2))) return 0;
if(DB(getVolume(x1,y1,z1,z2))) return 0;
return 1;
}
int getFactNum()
{
int ans=0,i,j;
FOR0(i,cnt)
{
FOR(j,i+1,cnt-1) if(isSame(F[i],F[j]))
{
break;
}
ans+=j>=cnt;
}
return ans;
}
double pToFace(Point a,face f)
{
double V=getVolume(p[f.a],p[f.b],p[f.c],a);
double s=getArea(p[f.a],p[f.b],p[f.c]);
return fabs(V/s);
}
double getMinDis(Point p)
{
double ans=1e50;
int i;
FOR0(i,cnt) ans=min(ans,pToFace(p,F[i]));
return ans;
}
};
_3DCH a;
int main()
{
while(scanf("%d",&a.n),a.n)
{
int i;
FOR0(i,a.n) a.p[i].Get();
a.construct();
int Q;
Point p;
RD(Q);
while(Q--)
{
p.Get();
printf("%.4lf\n",a.getMinDis(p));
}
}
return 0;
}