三维凸包

本文主要探讨了三维凸包的概念,并结合HDU4266题目,详细解析了三维凸包在ACM/ICPC竞赛中的应用,以及如何解决扔石头问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

三维凸包模板 hdu4266

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;
const int MAXN = 1100;
const double eps = 1e-9;
struct Point
{
     double x,y,z;
     Point(){}
     Point(double _x,double _y,double _z):x(_x),y(_y),z(_z){}
     Point operator -(const Point &P)
     {
           return Point(x-P.x, y-P.y, z-P.z);
     }  
     Point operator ^ (const Point &P)//叉积 
     {
           return Point(y*P.z - z * P.y, z * P.x - x * P.z, x*P.y - y * P.x);
     }
     double operator * (const Point &P)//点积 
     {
           return (x * P.x + y * P.y + z * P.z); 
     } 
     
};
struct CH3D
{
       struct face
       {
            int a,b,c;
            bool ok ;// 判断是否是凸包的面 
            face(){}
            face(int _a,int _b,int _c, bool _ok):a(_a),b(_b),c(_c),ok(_ok){}
            void init(int _a,int _b,int _c, bool _ok){
                 a = _a; b = _b; c =_c; ok = _ok;
            }
       };
       int n,num;
       Point p[MAXN]; 
       int g[MAXN][MAXN];//凸包表面的三角形
       face F[MAXN * 8];
       double vlen(const Point &a) //向量长度
       {
              return sqrt(a.x*a.x+a.y*a.y+a.z*a.z);
       }
       double area(Point &a,Point &b,Point &c)// 三角形面积*2
       {
              return vlen((b-a) ^ (c-a));
       } 
       double volume(Point &a, Point &b , Point &c ,Point &d)//四面体体积
       {
              return ((b-a)^(c-a)) * (d-a);
       }   
       double dblcmp(Point &P,face &f)                                    
       {
              Point m=p[f.b]-p[f.a];
              Point n=p[f.c]-p[f.a];
              Point t=P-p[f.a];
              return (m ^ n) * t;
       }  
       void deal(int P,int a,int b)
       {
            int f=g[a][b];   
            if(F[f].ok)
            {
                 if(dblcmp(p[P],F[f])>eps) dfs(P,f);
                 else
                 {
                     face add(b,a,P,1); 
                     g[P][b]=g[a][P]=g[b][a]=num;
                     F[num++]=add;
                 }
            }
       }
       void dfs(int p,int now)
       {
            F[now].ok=0;
            deal(p,F[now].b,F[now].a);
            deal(p,F[now].c,F[now].b);
            deal(p,F[now].a,F[now].c);
       }
       bool same(int s,int t)
       {
            Point &a=p[F[s].a];
            Point &b=p[F[s].b];
            Point &c=p[F[s].c];
            return fabs(volume(a,b,c,p[F[t].a]))<eps && fabs(volume(a,b,c,p[F[t].b]))<eps
                && fabs(volume(a,b,c,p[F[t].c]))<eps;
       }
       void solve()//构建三维凸包
       {
            face add; bool flag=true;
            num=0;
            if(n<4) return;
            for(int i=1;i<n;i++)//此段是为了保证前四个点不共面,若以保证,则可去掉
            {
                if(vlen(p[0]-p[i])>eps){
                       swap(p[1],p[i]);
                       flag=false; break;
                }
            }
            if(flag)   return;
            flag=true;
            for(int i=2;i<n;i++)//使前三点不共线
            {
                 if(vlen((p[0]-p[1])^(p[1]-p[i]))>eps)
                 {
                       swap(p[2],p[i]);
                       flag=false; break;
                 }
            }
            if(flag)   return;
            flag=true;
            for(int i=3;i<n;i++)//使前四点不共面
            {
                  if(fabs(((p[0]-p[1])^(p[1]-p[2]))*(p[0]-p[i]))>eps){
                        swap(p[3],p[i]);
                        flag=false; break;
                  }
            }
            if(flag) return;
            for(int i=0;i<4;i++)
            {
                   add.init((i+1)%4,(i+2)%4,(i+3)%4,true);
                   if(dblcmp(p[i],add)>0) swap(add.b,add.c);
                   g[add.a][add.b]=g[add.b][add.c]=g[add.c][add.a]=num;
                   F[num++]=add;
            }
            for(int i=4;i<n;i++){
                for(int j=0;j<num;j++) {
                     if(F[j].ok && dblcmp(p[i],F[j])>eps){
                          dfs(i,j); break;
                     }
                }
            }
            int tmp=num; num = 0;
            for(int i=0;i<tmp;i++)
                    if(F[i].ok) F[num++]=F[i];
       }
       double area()//表面积
       {
              double res=0.0;
              if(n==3){
                   //Point p=cross(P[0],P[1],P[2]);
                   res=vlen((p[1]-p[0])^(p[2]-p[0]))/2.0;
                   return res;
              }        
              for(int i=0;i<num;i++)
                 res+=vlen((p[F[i].b]-p[F[i].a]) ^ (p[F[i].c]-p[F[i].a]));
              return res/2.0;
       }
       double volume() //体积
       {
              double res=0.0;
              Point temp(0,0,0);
              for(int i=0;i<num;i++)
                 res+=((p[F[i].b]-p[F[i].a])^(p[F[i].c]-p[F[i].a])) * (temp-p[F[i].a]); 
              return fabs(res/6.0);
       }
       int triangle()//表面三角形个数 
       {
              return num;
       }
       int polygon()//表面多边形个数
       {
           int res = 0;
           for(int i=0,flag = 1; i<num;i++)
           {
                for(int j=0;j<i;j++)
                if(same(i,j)){
                      flag=0;break;
                 }
                res+=flag;
           }
           return res;
       }
       double getMinDis(Point Q)
       {
              double ans = 0x7fffffff;
              for (int i = 0; i < num;++i){
              ans = min(ans,
              volume(Q,p[F[i].a],p[F[i].b],p[F[i].c]) /area(p[F[i].a],p[F[i].b],p[F[i].c]));
              }
              return ans;
       }
       
}hull; 
int main()
{    while (scanf("%d",&hull.n)!=EOF)
    {
          if (hull.n ==0) break;
          for (int i = 0; i < hull.n;++i)
              scanf("%lf%lf%lf",&hull.p[i].x, &hull.p[i].y,&hull.p[i].z);
          hull.solve();
          int q; cin>>q;
          for (int i = 0; i < q;++i)
          {
              Point Q;
              scanf("%lf%lf%lf",&Q.x,&Q.y,&Q.z);
              printf("%.4lf\n", hull.getMinDis(Q));
          }
    }
    return 0;
}


2013 ACM/ICPC 长沙邀请赛- I 题   Throw the stones

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
const int MAXN = 10002;
const double eps = 1e-9;
int child;
double last,D;
struct Point
{
     double x,y,z;
     Point(){}
     Point(double _x,double _y,double _z):x(_x),y(_y),z(_z){}
     Point operator -(const Point &P)
     {
           return Point(x-P.x, y-P.y, z-P.z);
     }  
     Point operator ^ (const Point &P)//叉积 
     {
           return Point(y*P.z - z * P.y, z * P.x - x * P.z, x*P.y - y * P.x);
     }
     double operator * (const Point &P)//点积 
     {
           return (x * P.x + y * P.y + z * P.z); 
     } 
     
};
struct CH3D
{
       struct face
       {
            int a,b,c;
            bool ok ;// 判断是否是凸包的面 
            face(){}
            face(int _a,int _b,int _c, bool _ok):a(_a),b(_b),c(_c),ok(_ok){}
            void init(int _a,int _b,int _c, bool _ok){
                 a = _a; b = _b; c =_c; ok = _ok;
            }
       };
       int n,num;
       Point p[MAXN]; 
       map<int,int> g[MAXN];//凸包表面的三角形
       face F[MAXN * 10];
       double vlen(const Point &a) //向量长度
       {
              return sqrt(a.x*a.x+a.y*a.y+a.z*a.z);
       }
       double area(Point &a,Point &b,Point &c)// 三角形面积*2
       {
              return vlen((b-a) ^ (c-a));
       } 
       double volume(Point &a, Point &b , Point &c ,Point &d)//四面体体积
       {
              return ((b-a)^(c-a)) * (d-a);
       }   
       double dblcmp(Point &P,face &f)                                    
       {
              Point m=p[f.b]-p[f.a];
              Point n=p[f.c]-p[f.a];
              Point t=P-p[f.a];
              return (m ^ n) * t;
       }  
       void deal(int P,int a,int b)
       {
            int f=g[a][b];   
            if(F[f].ok)
            {
                 if(dblcmp(p[P],F[f])>eps) dfs(P,f);
                 else
                 {
                     D += (p[a]^p[P]) * p[b];  
                     face add(b,a,P,1); 
                     g[P][b]=g[a][P]=g[b][a]=num;
                     F[num++]=add;
                 }
            }
       }
      void dfs(int P,int now)
       {
            D-=(p[F[now].b] ^ p[F[now].c] )* p[F[now].a];
            F[now].ok=0;
            deal(P,F[now].b,F[now].a);
            deal(P,F[now].c,F[now].b);
            deal(P,F[now].a,F[now].c);
       }
       bool same(int s,int t)
       {
            Point &a=p[F[s].a];
            Point &b=p[F[s].b];
            Point &c=p[F[s].c];
            return fabs(volume(a,b,c,p[F[t].a]))<eps && fabs(volume(a,b,c,p[F[t].b]))<eps
                && fabs(volume(a,b,c,p[F[t].c]))<eps;
       }
       void init()
       {
            face add;
            for(int i=0;i<4;i++)
            {
                   add.init((i+1)%4,(i+2)%4,(i+3)%4,true);
                   if(dblcmp(p[i],add)>0) swap(add.b,add.c);
                   g[add.a][add.b]=g[add.b][add.c]=g[add.c][add.a]=num;
                   F[num++]=add;
            }
       }
       void update(int i)
       {
            for(int j=0;j<num;j++) 
            if(F[j].ok && dblcmp(p[i],F[j])>eps){
                dfs(i,j); break;
            }
       }
       void solve()//构建三维凸包
       {
            face add; bool flag=true;
            num=0;
            if(n<4) return;
            for(int i=1;i<n;i++)//此段是为了保证前四个点不共面,若以保证,则可去掉
            {
                if(vlen(p[0]-p[i])>eps){
                       swap(p[1],p[i]);
                       flag=false; break;
                }
            }
            if(flag)   return;
            flag=true;
            for(int i=2;i<n;i++)//使前三点不共线
            {
                 if(vlen((p[0]-p[1])^(p[1]-p[i]))>eps)
                 {
                       swap(p[2],p[i]);
                       flag=false; break;
                 }
            }
            if(flag)   return;
            flag=true;
            for(int i=3;i<n;i++)//使前四点不共面
            {
                  if(fabs(((p[0]-p[1])^(p[1]-p[2]))*(p[0]-p[i]))>eps){
                        swap(p[3],p[i]);
                        child = i; init();
                        for (int j = 4; j<=child;++j) update(j);
                        last = volume();
                        flag=false; break;
                  }
            }
            if(flag) return;
            for(int i=child+1;i<n;i++) {
                    D = 0;update(i);D/=6.0;
                    if (D>last+eps){
                       child = i;
                       last = D;
                    }
            }
            int tmp=num; num = 0;
            for(int i=0;i<tmp;i++)
                    if(F[i].ok) F[num++]=F[i];
       }
       double area()//表面积
       {
              double res=0.0;
              if(n==3){
                   //Point p=cross(P[0],P[1],P[2]);
                   res=vlen((p[1]-p[0])^(p[2]-p[0]))/2.0;
                   return res;
              }        
              for(int i=0;i<num;i++)
                 res+=vlen((p[F[i].b]-p[F[i].a]) ^ (p[F[i].c]-p[F[i].a]));
              return res/2.0;
       }
       double volume() //体积
       {
              double res=0.0;
              Point temp(0,0,0);
              for(int i=0;i<num;i++)
                if (F[i].ok)
                 res+=((p[F[i].b]-p[F[i].a])^(p[F[i].c]-p[F[i].a])) * (temp-p[F[i].a]); 
                 //res +=(p[F[i].b] ^ p[F[i].c]) *p[F[i].a];
              return fabs(res/6.0);
       }
       int triangle()//表面三角形个数 
       {
              return num;
       }
       int polygon()//表面多边形个数
       {
           int res = 0;
           for(int i=0,flag = 1; i<num;i++)
           {
                for(int j=0;j<i;j++)
                if(same(i,j)){
                      flag=0;break;
                 }
                res+=flag;
           }
           return res;
       }
       double getMinDis(Point Q)
       {
              double ans = 0x7fffffff;
              for (int i = 0; i < num;++i){
              ans = min(ans,
              volume(Q,p[F[i].a],p[F[i].b],p[F[i].c]) /area(p[F[i].a],p[F[i].b],p[F[i].c]));
              }
              return ans;
       }
       
}hull; 
int main()
{
    int test =0;
    while (scanf("%d",&hull.n)!=EOF)
    {
          test ++;
          child = 0;last = 0;
          for (int i = 0; i < hull.n;++i)
              scanf("%lf%lf%lf",&hull.p[i].x, &hull.p[i].y,&hull.p[i].z);
          hull.solve();
          printf("Case #%d:\n%d %.2lf\n",test, child+1,last);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值