\(\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. Spring学习八

    1: Tomcat容器四个等级? Container, Engine,  Servlet容器, Context 真正管理Servlet的容器是Context容器:一个context对应一个web工程. ...

  2. sql---left join;right join;inner join---区别

    sql---left join;right join;inner join---区别 分为以下几类: 1.内联接(典型的联接运算,使用像 = 或 <> 之类的比较运算符).包括相等联接和自 ...

  3. [转]Missing MSS Settings in Security Options of Group Policy (GPO)

    I'm currently working on a new Windows Server 2012 and Windows 8 project. As part of that project is ...

  4. 解决CentOS遇到Qt编译(error: cannot find -lGL)

    笔者CentOS 6.5 64位,安装完成Qt5.5.1.随意新建一个Qt Widgets Application. 结果遇到Qt编译问题,提示信息如下: error: cannot find -lG ...

  5. 问题:Oracle出发器;结果:1、Oracle触发器详解,2、Oracle触发器示例

    ORACLE触发器详解 本篇主要内容如下: 8.1 触发器类型 8.1.1 DML触发器 8.1.2 替代触发器 8.1.3 系统触发器 8.2 创建触发器 8.2.1 触发器触发次序 8.2.2 创 ...

  6. c:if标签数据回显判断是否选中

    <form action="/brand/list.do" method="post" style="padding-top:5px;" ...

  7. 框架之 hibernate之关联关系映射

    案例:完成CRM的联系人的保存操作 需求分析 1. 因为客户和联系人是一对多的关系,在有客户的情况下,完成联系人的添加保存操作 技术分析之Hibernate的关联关系映射之一对多映射(重点) 1. J ...

  8. Python 使用其他邮件服务商的 SMTP 访问(QQ、网易、163、Google等)发送邮件

    163邮箱SMTP授权 使用Python SMTP发送邮件 # -*- coding:utf-8 -*- from __future__ import print_function __author_ ...

  9. python常用uuid模块

    uuid.uuid4(),会根据我们当前的网卡和时间生成的一个随机字符串. 注意:uuid.uuid4()生成的是一个对象,需要强转为字符串. uid = str(uuid.uuid4()) #当前网 ...

  10. redhat图形界面启动后出现桌面但是没有登录界面解决办法

    redhat图形界面启动后出现桌面但是没有登录界面解决办法 2014年07月11日 10:50:10 阅读数:7931 redhat Linux一直用着好好地,今天打开只有图像界面背景,没有出现登陆界 ...