zoukankan      html  css  js  c++  java
  • P4724 【模板】三维凸包

    (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;
    }
    
  • 相关阅读:
    python第十一天
    python第七天(字符编码,字符与字节,文件操作)
    python第六天(元组、字典、集合)
    python第五天
    python第四天
    根据数据库文件,查找对应的数据库
    Windows 路径问题
    32位及64位操作系统的程序问题
    好玩的获取目录信息的例子[C#]
    C# 反射相关的东西
  • 原文地址:https://www.cnblogs.com/olinr/p/10205259.html
Copyright © 2011-2022 走看看