HDU 4273 Rescue(三维凸包重心)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4273

题意:求三维凸包重心到表面的最小距离。

思路:模板。



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-(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);

	}



	Point operator*(double t)

	{

	    return Point(x*t,y*t,z*t);

	}



    double operator^(Point p)

	{

		return x*p.x+y*p.y+z*p.z;

	}



	Point operator/(double t)

	{

	    return Point(x/t,y/t,z/t);

	}



	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;

    }



    Point getCenter()

    {

        Point ans(0,0,0),o(0,0,0);

        double V=0,temp;

        int i;

        FOR0(i,cnt)

        {

            temp=getVolume(o,p[F[i].a],p[F[i].b],p[F[i].c]);

            ans=ans+(o+p[F[i].a]+p[F[i].b]+p[F[i].c])/4*temp;

            V+=temp;

        }

        return ans/V;

    }

};



_3DCH a;



int main()

{

    while(scanf("%d",&a.n)!=-1)

    {

        int i;

        FOR0(i,a.n) a.p[i].Get();

        a.construct();

        printf("%.3lf\n",a.getMinDis(a.getCenter()));

    }

    return 0;

}

  

你可能感兴趣的:(HDU)