\(\color{#0066ff}{题目描述}\)

给出空间中n个点,求凸包表面积。

\(\color{#0066ff}{输入格式}\)

第一行一个整数n,表示点数。

接下来n行,每行三个实数x,y,z描述坐标。

\(\color{#0066ff}{输出格式}\)

输出凸包表面积,保留3位小数。

\(\color{#0066ff}{输入样例}\)

4
0 0 0
1 0 0
0 1 0
0 0 1

\(\color{#0066ff}{输出样例}\)

2.366

\(\color{#0066ff}{数据范围与提示}\)

n≤2000

\(\color{#0066ff}{题解}\)

增量法

把每个面,分成正面,反面

先选出3个点(构成一个面)

每次加点

先把当前的点能看见的面全部删除(最后的凸包一定不存在能被某个点看见的面)

然后枚举前面的面中的某两个点,与当前点构成新面,成立则加入

最后的就是凸包的面‘

为了防止共面共线问题,可以在精度允许范围内微调一下坐标

#include<bits/stdc++.h>
using namespace std;
#define LL long long
LL in() {
char ch; int x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const double eps = 1e-9;
const int maxn = 2050;
struct node {
double x, y, z;
node(double x = 0, double y = 0, double z = 0): x(x), y(y), z(z) {}
node operator - (const node &b) const {
return node(x - b.x, y - b.y, z - b.z);
}
node operator ^ (const node &b) const {
return node(y * b.z - z * b.y, z * b.x - x * b.z, x * b.y - y * b.x);
}
double operator * (const node &b) const {
return x * b.x + y * b.y + z * b.z;
}
void init() {
x = x + ((double)rand() / (double)RAND_MAX - 0.5) * eps * 10;
y = y + ((double)rand() / (double)RAND_MAX - 0.5) * eps * 10;
z = z + ((double)rand() / (double)RAND_MAX - 0.5) * eps * 10;
}
double mo() {
return sqrt(*this * *this);
}
bool jud() {
return fabs(x) <= eps && fabs(y) <= eps && fabs(z) <= eps;
}
}e[maxn]; struct plane {
int v[3];
plane(int a = 0, int b = 0, int c = 0) { v[0] = a, v[1] = b, v[2] = c; }
int &operator [] (const int &b) {
return v[b];
}
node F() const {
return ((e[v[1]] - e[v[0]]) ^ (e[v[2]] - e[v[0]]));
}
bool cansee(node x) const {
return (x - e[v[0]]) * F() > 0;
}
};
int n, cnt;
bool vis[maxn][maxn];
void init() {
n = in();
for(int i = 1; i <= n; i++) {
node o;
scanf("%lf%lf%lf", &o.x, &o.y, &o.z);
for(int j = 1; j <= cnt; j++) if((e[j] - o).jud()) goto cant;
e[++cnt] = o;
cant:;
}
n = cnt;
for(int i = 1; i <= n; i++) e[i].init();
}
double D() {
double ans = 0;
using std::vector;
vector<plane> c;
c.push_back(plane(1, 2, 3));
c.push_back(plane(3, 2, 1));
for(int i = 4; i <= n; i++) {
vector<plane> q;
for(int j = 0; j < (int)c.size(); j++) {
plane t = c[j];
bool flag = t.cansee(e[i]);
if(!flag) q.push_back(c[j]);
for(int k = 0; k < 3; k++)
vis[t[k]][t[(k + 1) % 3]] = flag;
}
for(int j = 0; j < (int)c.size(); j++)
for(int k = 0; k < 3; k++) {
int a = c[j][k], b = c[j][(k + 1) % 3];
if(vis[a][b] != vis[b][a] && vis[a][b])
q.push_back(plane(a, b, i));
}
c = q;
}
for(int i = 0; i < (int)c.size(); i++) ans += c[i].F().mo();
return ans;
} int main() {
init();
printf("%.3f", D() / 2.0);
return 0;
}

P4724 【模板】三维凸包的更多相关文章

  1. luogu P4724 模板 三维凸包

    LINK:三维凸包 一个非常古老的知识点.估计也没啥用. 大体上了解了过程 能背下来就背下来吧. 一个bf:暴力枚举三个点 此时只需要判断所有的点都在这个面的另外一侧就可以说明这个面是三维凸包上的面了 ...

  2. [Luogu4724][模板]三维凸包(增量构造法)

    1.向量点积同二维,x1y1+x2y2+x3y3.向量叉积是行列式形式,(y1z2-z1y2,z1x2-x1z2,x1y2-y1x2). 2.增量构造法: 1)首先定义,一个平面由三个点唯一确定.一个 ...

  3. 题解-洛谷P4724 【模板】三维凸包

    洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...

  4. hdu4266(三维凸包模板题)

    /*给出三维空间中的n个顶点,求解由这n个顶点构成的凸包表面的多边形个数. 增量法求解:首先任选4个点形成的一个四面体,然后每次新加一个点,分两种情况: 1> 在凸包内,则可以跳过 2> ...

  5. POJ3528 HDU3662 三维凸包模板

    POJ3528 HDU3662 第一道题 给定若干点 求凸包的表面积,第二题 给定若干点就凸包的面数. 简单说一下三维凸包的求法,首先对于4个点假设不共面,确定了唯一四面体,对于一个新的点,若它不在四 ...

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

    题意: 两个凸多面体,可以任意摆放,最多贴着,问他们重心的最短距离. 解法: 由于给出的是凸多面体,先构出两个三维凸包,再求其重心,求重心仿照求三角形重心的方式,然后再求两个多面体的重心到每个多面体的 ...

  7. hdu4273Rescue(三维凸包重心)

    链接 模板题已不叫题.. 三维凸包+凸包重心+点到平面距离(体积/点积)  体积-->混合积(先点乘再叉乘) #include <iostream> #include<cstd ...

  8. hdu 4273 2012长春赛区网络赛 三维凸包中心到最近面距离 ***

    新模板 /* HDU 4273 Rescue 给一个三维凸包,求重心到表面的最短距离 模板题:三维凸包+多边形重心+点面距离 */ #include<stdio.h> #include&l ...

  9. bzoj 1209: [HNOI2004]最佳包裹 三维凸包

    1209: [HNOI2004]最佳包裹 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 160  Solved: 58[Submit][Status] ...

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

    1964: hull 三维凸包 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 54  Solved: 39[Submit][Status][Discuss ...

随机推荐

  1. ThreadPoolExecutor的corePoolSize和maximumPoolSize

    按照JDK文档的描述, 如果池中的实际线程数小于corePoolSize,无论是否其中有空闲的线程,都会给新的任务产生新的线程 如果池中的线程数>corePoolSize and <max ...

  2. 2015.12.12 DataGridveiw中添加checkbox列

    最简单的办法是通过DataTable来添加 DataTable中添加bool类型的列 dtpdf.Columns.Add("入库", typeof(bool)); DataRow ...

  3. Nginx简单入门教学,包学包会,让你不再依赖伪大神!

    这篇教程简单介绍了 nginx 并且讲解了一些 nginx 可以解决的简单任务.这里,我们假设 nginx 已经安装在读者的机器上.如果没有,可以看一下如何安装 nginx.这篇教程主要讲解的是如果启 ...

  4. javascript——对象的概念——创建对象与销毁对象

    一.创建对象 1.创建空对象 方式一: var o ={};o; //Object {} typeof(o); //"object" 方式二: var o=new Object() ...

  5. windows下启动命令行

    1.当前目录打开命令窗口:shift+鼠标右键,然后打开命令窗口 2.查看监听的端口:netstat – ano

  6. ROS探索总结(二)——ROS总体框架

    个人分类: ROS 所属专栏: ROS探索总结   一.  总体结构        根据ROS系统代码的维护者和分布来标示,主要有两大部分:      (1)main:核心部分,主要由Willow G ...

  7. 在html中打开PDF

    <object classid="clsid:CA8A9780-280D-11CF-A24D-444553540000" width="990" heig ...

  8. SQl Server 与数据库的第一次相遇

    数据库就是 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库,简单说就是存储在硬盘上的文件. 市面上常见数据库有<关系数据库系统>: ORACLE(甲骨文).DB2.S ...

  9. Windows Live Writer 使用指南

    一.简介 Windows Live Writer 是一个强大的离线博客编辑工具,通过它可以离线编辑内容丰富的博文,除了自身强大的编辑功能之外,还提供了接口,让其它开发人员通过插件提供工具自身没有提供的 ...

  10. zedboard:使用ISE和modelsim搭建仿真环境 标签: zedboardfpgamodelsimise 2017-03-03 14:00 528人阅读

    详细步骤: 产生ISE仿真库文件 开始->所有程序->xilinx design tools->simulation library compilation wizard.路径可能不 ...