最佳包裹

news/2025/3/19 11:26:00/文章来源:https://www.cnblogs.com/dingxingdi/p/18341467

求三维凸包用增量法求解

假设我们已经维护好了前面的点的凸包,对于新加入的点:

如果这个点在凸包内部显然那就不用管了

如果这个点在凸包外部,那么考虑如下情况:

将新点\(P_r\)当做光源,照的到的面全部删掉,照不到的面保留下来即可

如何判断一个面是否能够被照到:取多面体外侧为正方向,则对于某一个面,如果光源在其正侧那么能被照到,否则不行;具体判断的时候,在平面上取一个点\(a\),则判断由\(a,P_r\)组成的向量与平面的法向量的叉积即可

维护面的时候,我们都是维护的三角形(如果一个面不是三角形我们对其进行三角剖分),存储三角形的三个点就好了(按照逆时针方向存储);一共有\(n\)个点,每个面对应三条边,但是每条边会被重复数两次,所以设面有\(m\)个,边有\(k\)个,则\(3m=2k\),代入多面体欧拉定理得,\(m=2n-4,k=3n-6\),可知时间复杂度为\(O(n^2)\)

如何找出分界线:设\(g[i][j]\)表示由\(i\)指向\(j\)的这条向量是否是分界线,那么由于我们是按照逆时针方向存储的三个点,如下图

我们只需要判断\(\vec{ij}\)\(\vec{ji}\)表示的两个面中,一个可以被照到,另一个不能被照到就好了

代码见下:

#include<bits/stdc++.h>
#define ll long long
#define Vector Point
using namespace std;
const int N=2010;
const double eps=1e-10;
double Rand()
{return rand()/(double)RAND_MAX;//RAND_MAX是宏定义,表示rand()能返回的最大整数 
}
double reps()
{return (Rand()-0.5)*eps;
}
struct Point
{double x,y,z;Point(double a=0,double b=0,double c=0):x(a),y(b),z(c){}void shake(){x+=reps(),y+=reps(),z+=reps();}
}p[N];
Vector Cross(Vector a,Vector b)
{return Vector{a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x};
}
bool vis[N][N];
int cnt,n;
Point operator - (Point a,Point b){return Point(a.x-b.x,a.y-b.y,a.z-b.z);}
double get_length(Vector a)
{return sqrt(a.x*a.x+a.y*a.y+a.z*a.z);
}
struct Face
{int v[3];//存储这一个面的三个点的编号,逆时针方向 double area(){return get_length(Cross(p[v[1]]-p[v[0]],p[v[2]]-p[v[0]]))/2;}
}f[N<<2],C[N<<2];
double operator * (Vector a,Vector b){return a.x*b.x+a.y*b.y+a.z*b.z;}
bool see(Face a,Point b)
{return (b-p[a.v[0]])*Cross(p[a.v[1]]-p[a.v[0]],p[a.v[2]]-p[a.v[0]])>0;//进行了微小扰动,不会出现等于0的情况
}
void Convex_3D()
{f[++cnt]={1,2,3},f[++cnt]={3,2,1};//对于前三个点的凸包,我们认为是两张一模一样的平面,但是方向不同//如果{1,2,3}从某一个方向看是顺时针,那么我们就认为我们从另一个方向看//总之可以找到一个方向使得{1,2,3}为逆时针,{3,2,1}是顺时针//于是此时认为这个方向为正方向,{3,2,1}的正方向就是这个方向的反方向 for(int i=4,cc=0;i<=n;i++){bool v;for(int j=1;j<=cnt;j++){v=see(f[j],p[i]);//判断是否看得见 if(!v) C[++cc]=f[j];for(int k=0;k<3;k++) vis[f[j].v[k]][f[j].v[(k+1)%3]]=v;//vis[i][j]用来记录向量ij所表示的面(左手边)是否被看得见 } 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]={x,y,i};//添加新的面,注意三个点的顺序,要保证逆时针 } for(int j=1;j<=cc;j++) f[j]=C[j];cnt=cc;cc=0;}
}
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].z);p[i].shake();//这一步在随机微小扰动,为什么要下文说明 }Convex_3D();double ans=0;for(int i=1;i<=cnt;i++) ans+=f[i].area();printf("%.3f\n",ans);return 0;
}

说明一下为什么要微小扰动:这是为了防止出现四点共面的情况。如果出现了四点共面的情况,可能会导致各种错误。举一个例子,比如对于前四个点共面,那么在加入第四个点的时候,由上面的代码判断的是之前三个点形成的凸包的两个面都看不见,就都会算进去,而且现在不知道新加入的三角形如何剖分(剖分方式很多),所以不行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/777592.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数值分析方法

数值分析复习笔记数值分析方法 数值方法可以用近似方法来理解 对于一些得不到解析解否则解析解计算难度太大的问题,如何用较少的计算得到相对较好(满足精度要求)的数值解、近似解。数值分析最基本的立足点是容许误差 例子:近似计算基本方法:离散化(e.g. 数值积分) 递推法(将…

rocksdb安装与使用

首先要安装gcc 7.3以上版本,依赖于c++ 17.参见gcc 7安装及4.8.5和7.5并存。 需要rpm方式或源码安装gflags 2.2,否则系统可能内置了gflags 2.1,从而导致链接时一直找不到gflags库。如下:/tmp/ccUXmr9R.o: In function `__static_initialization_and_destruction_0(int, int)…

WPF【无限滚动图片浏览】自定义控件

自定义控件自定义控件是我比较陌生的一个主题。我好久没练习过wpf了,需要巩固记忆。我想了一会儿,打开动漫之家,忽然觉得这个看漫画的图片浏览控件有意思。于是特地花了一天做了这个图片控件。我原本以为很容易,但实际上并不简单。这个图片浏览控件比我想象中要难许多,有技…

矩阵乘法内核优化CUDA杂谈

矩阵乘法内核优化CUDA杂谈矩阵乘法内核优化CUDA杂谈How to Optimize a CUDA Matmul Kernel for cuBLAS-like Performance: a Workloghttps://siboehm.com/articles/22/CUDA-MMM在这篇文章中,我将迭代优化用CUDA编写的矩阵乘法的实现。我的目标不是构建cuBLAS的替代品,而是深入…

Cocos Creator 3.8.x bundle核心知识点

bundle官网知识文档: https://docs.cocos.com/creator/3.8/manual/zh/asset/bundle.html bundle核心知识点如下:

python-sum()返回所有元素的总和

lb=[10,30,5,40,89,100] i=sum(lb) #返回所有元素的总和 #参数:序列 print(i)

python-max()返回最大值

lb=[10,30,5,40,89,100] i=max(lb) #返回最大值 #参数:序列 print(i)

python-min返回最小值

lb=[10,30,5,40,89,100] i=min(lb) #返回最小值 #参数:序列 print(i)

windows 隐藏桌面了解此图片

1. 桌面上有了解此图片图标无法删除这是因为在windows背景设置中选择了Window聚焦。如果想关闭可以选择其他选项。如果不想关闭Window聚焦还想隐藏桌面了解此图片图标,可以参考下面设置。 2. 打开注册表 win + x打开运行,输入regedit 回车。 3. 新建或修改注册表 在注册表的地…

[vue3] vue3对比vue2优化项简要概述

Vue2存在源码可维护性差、性能问题和API兼容性不足等缺点。Vue3通过monorepo管理、TypeScript开发、性能优化和引入Composition API等方式,显著提升了源码可维护性、编程体验、TypeScript支持和逻辑复用实践,从源码、性能和语法API三方面进行了优化。不足与展望 Vue2的不足源…

DevOps实践

DevOps 一、DevOps介绍 软件开发最开始是由两个团队组成:开发计划由开发团队从头开始设计和整体系统的构建。需要系统不停的迭代更新。 运维团队将开发团队的Code进行测试后部署上线。希望系统稳定安全运行。这看似两个目标不同的团队需要协同完成一个软件的开发。 在开发团队…

高考结束咯,录取结束咯,通知书下来咯,即将开启大学生活咯!

高考结束咯,录取结束咯,通知书下来咯,即将开启大学生活咯!高考结束咯,自我感觉良好,期待着结果出来 结果高考成绩一出来吓我一大跳,657分,比预想中的高了几十分,哈哈哈哈哈哈但是我最关心的人却考砸了,也不知道是不是我的问题(虽然ta比我高),真是逆天!下面是高考…