Luogu 4724 三维凸包

Luogu 4724 三维凸包

  • 增量法,维护当前凸包,每次加入一个点 \(P\) ,视其为点光源,将可见面删去,新增由"晨昏线"(分割棱)与 \(P\) 构成的平面.
  • 注意每个平面表面积为其三个端点算出的法向量模长一半.
  • 参考讲解.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
inline int read()
{
    int x=0;
    bool pos=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            pos=0;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return pos?x:-x;
}
const int MAXN=2e3+10;
const double eps=1e-9;
double Rand()
{
    return rand()/(double)RAND_MAX;
}
int dcmp(double x)
{
    return fabs(x)<eps?0:(x>0?1:-1);
}
struct point{
    double x,y,z;
    point(double x=0,double y=0,double z=0):x(x),y(y),z(z) {}
    void randtrans()
        {
            x+=(Rand()-0.5)*eps;
            y+=(Rand()-0.5)*eps;
            z+=(Rand()-0.5)*eps;
        }
};
point A[MAXN];
struct Vector{
    double x,y,z;
    Vector(double x=0,double y=0,double z=0):x(x),y(y),z(z) {}
    double modulus()
        {
            return sqrt(x*x+y*y+z*z);
        }
};
Vector vec(point a,point b)
{
    return Vector(b.x-a.x,b.y-a.y,b.z-a.z);
}
Vector cross(Vector a,Vector b)
{
    return Vector(a.y*b.z-b.y*a.z,-(a.x*b.z-b.x*a.z),a.x*b.y-b.x*a.y);
}
double cdot(Vector a,Vector b)
{
    return a.x*b.x+a.y*b.y+a.z*b.z;
}
struct Plane{
    int v[3];
    Vector Normal()
        {
            return cross(vec(A[v[0]],A[v[1]]),vec(A[v[0]],A[v[2]]));
        }
    double area()
        {
            return Normal().modulus()/2.0;
        }
};
Plane getplane(int a,int b,int c)
{
    Plane res;
    res.v[0]=a;
    res.v[1]=b;
    res.v[2]=c;
    return res;
}
bool insight(Plane a,point p)
{
    Vector w=a.Normal();
    return dcmp(cdot(w,vec(A[a.v[0]],p)))>0;
}
int n;
Plane f[MAXN],C[MAXN];
int vis[MAXN][MAXN];
double ConvexHullSurfaceArea()
{
    int cnt=0;
    f[++cnt]=(Plane){1,2,3};
    f[++cnt]=(Plane){3,2,1};
    for(int i=4,cc=0;i<=n;i++)
    {
        for(int j=1,v;j<=cnt;j++)
        {
            if(!(v=insight(f[j],A[i])))
                C[++cc]=f[j];
            for(int k=0;k<3;k++)
                vis[f[j].v[k]][f[j].v[(k+1)%3]]=v;
        }
        for(int j=1;j<=cnt;j++)
            for(int k=0;k<3;k++)
            {
                int x=f[j].v[k],y=f[j].v[(k+1)%3];
                if(vis[x][y]&&!vis[y][x])
                    C[++cc]=(Plane){x,y,i};
            }
        for(int j=1;j<=cc;j++)
            f[j]=C[j];
        cnt=cc;cc=0;
    }
    double ans=0;
    for(int i=1;i<=cnt;++i)
        ans+=f[i].area();
    return ans;
}
int main()
{
    n=read();
    for(int i=1;i<=n;++i)
        {
            scanf("%lf%lf%lf",&A[i].x,&A[i].y,&A[i].z);
            A[i].randtrans();
        }
    double ans=ConvexHullSurfaceArea();
    printf("%.3lf\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/jklover/p/10388835.html

时间: 2024-10-10 22:46:26

Luogu 4724 三维凸包的相关文章

POJ3528 HDU3662 三维凸包模板

POJ3528 HDU3662 第一道题 给定若干点 求凸包的表面积,第二题 给定若干点就凸包的面数. 简单说一下三维凸包的求法,首先对于4个点假设不共面,确定了唯一四面体,对于一个新的点,若它不在四面体内,为了让它进入凸包, 则对于所有凸包上的边,若边的一面是该点可以看到的而另一面看不到,则该点与该边构成的面要加入凸包. 模板代码非常清晰, #include<stdio.h> #include<algorithm> #include<string.h> #includ

POJ 2225 / ZOJ 1438 / UVA 1438 Asteroids --三维凸包,求多面体重心

题意: 两个凸多面体,可以任意摆放,最多贴着,问他们重心的最短距离. 解法: 由于给出的是凸多面体,先构出两个三维凸包,再求其重心,求重心仿照求三角形重心的方式,然后再求两个多面体的重心到每个多面体的各个面的最短距离,然后最短距离相加即为答案,因为显然贴着最优. 求三角形重心见此: http://www.cnblogs.com/whatbeg/p/4234518.html 代码:(模板借鉴网上模板) #include <iostream> #include <cstdio> #in

三维凸包模板

poj3528 参照 #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> using namespace std; #define inf 0x7fffffff #define max(a,b) (a>b?a:b) #define min(a,b) (a<b?a:b) #define eps 1e-7 #define MAXV 505 //三维点 s

hdu4266(三维凸包模板题)

/*给出三维空间中的n个顶点,求解由这n个顶点构成的凸包表面的多边形个数. 增量法求解:首先任选4个点形成的一个四面体,然后每次新加一个点,分两种情况: 1> 在凸包内,则可以跳过 2> 在凸包外,找到从这个点可以"看见"的面,删除这些面, 然后对于一边没有面的线段,和新加的这个点新建一个面,至于这个点可以看见的面, 就是求出这个面的方程(可以直接求法向量). */ #include<iostream> #include<cmath> #includ

bzoj 1964: hull 三维凸包 计算几何

1964: hull 三维凸包 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 54  Solved: 39[Submit][Status][Discuss] Description 三维凸包问题是一个基础的三维计算几何问题,不过这次你只需要做一个简单版的三维凸包问题就行了. Input 输入数据一共有若干行,每行三个整数,表示一个点的坐标.点的个数为五个. Output 输出一个实数,保留两位小数,表示三维凸包的体积. Sample Input 0

Hdu 3662 3D Convex Hull(三维凸包)

题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3662 思路:三维凸包模板. #include<cstdio> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #define PR 1e-8 #define N 510 using namespace std; struct TPoint { doub

hdu4449Building Design(三维凸包+平面旋转)

链接 看了几小时也没看懂代码表示的何意..无奈下来问问考研舍友. 还是考研舍友比较靠谱,分分钟解决了我的疑问. 可能三维的东西在纸面上真的不好表示,网上没有形象的题解,只有简单"明了"的讲解. 这题说起来很简单,求下三维凸包,枚举每一个面,进行坐标旋转,使得当前面作为xoy面时的其他坐标,然后求下投影面的凸包的面积. 为什么要旋转面而不直接算点到面的距离,是因为投影的面积没有办法算. 面旋转时是怎么旋转的,首先求得当前面的法向量p1,再求得它与向量e(0,0,1)的法向量pp,所有的点

hdu4273Rescue(三维凸包重心)

链接 模板题已不叫题.. 三维凸包+凸包重心+点到平面距离(体积/点积)  体积-->混合积(先点乘再叉乘) 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #include<cmath> 8 #include<

sgu290:Defend the Milky Way(三维凸包)

题目大意: 给出空间中 n(1≤n≤100) 个点,求出其凸包.如果有点在凸包的面或棱上,也要将其算进凸包中,将答案按字典序输出. 分析: 首先我就不吐槽 sgu 坑爹的输入了... 主要就是求解三维凸包,至于凸包面或棱上的点可以在求出凸包后再加进去.凸包上每个面都是三角形,如果在平面中就类似三角剖分一般. 这里采用的是O(n2)的增量法,主要算法流程就是: (1) 初始化一个未退化的四面体: (2) 如果新点在凸包内或凸包上,忽视掉: (3) 如果新点在凸包外,删去它可以看到的面,并将其并入整