首页 > 其他分享 >最佳包裹

最佳包裹

时间:2024-08-04 09:27:53浏览次数:6  
标签:return Point double 凸包 最佳 Vector 包裹 方向

求三维凸包用增量法求解

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

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

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

将新点\(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;
}

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

标签:return,Point,double,凸包,最佳,Vector,包裹,方向
From: https://www.cnblogs.com/dingxingdi/p/18341467

相关文章

  • Python爬虫技术 第32节 最佳实践和常见问题
    Python爬虫技术是一种用于从网站上自动抓取数据的技术。它涉及到网络请求、HTML解析、数据提取等多个环节。下面我将详细介绍Python爬虫的最佳实践以及一些常见的问题解决方法,包括日志记录和错误报告、爬虫维护和更新等方面。Python爬虫基础架构一个典型的Python爬虫程序......
  • 从编程小白到编程大神:大学新生的最佳入门攻略
    大学生活即将开始,作为一名编程小白,你或许对编程世界充满了好奇和向往,但也有些许的忐忑。编程是一门充满挑战的学科,但也是一项能为你打开无数可能性的大门的技能。本文将为你提供一份详细的攻略,帮助你从零开始,逐步成长为一名编程大神。一、明确学习目标在开始编程之旅之前,明确......
  • 如何通过MultiIndex查询MultiIndex并选择“最佳”行?
    假设我有一个MultiIndexbyMultiIndexDataFrame类似于这里生成的:importpandasaspddata_frame_rows=pd.MultiIndex.from_arrays([[],[],[]],names=("car","engine","wheels"))data_frame_columns=pd.MultiIndex.fr......
  • 返回列中负数最多的组的最佳方法是什么?
    我的数据帧是:importpandasaspddf=pd.DataFrame({'a':[-3,-1,-2,-5,10,-3,-13,-3,-2,1,2,-100],})预期输出:a0-31-12-23-5逻辑:我想返回最大的负数条纹。如果有多个连续最大,我想返回第一个连续。......
  • 2024 年五大最佳构建内部工具的开源项目
    ......
  • InternVL 最佳实践 swift微调
    InternVL最佳实践本篇文档涉及的模型如下:internvl-chat-v1_5internvl-chat-v1_5-int8mini-internvl-chat-2b-v1_5mini-internvl-chat-4b-v1_5internvl2-1binternvl2-2binternvl2-4binternvl2-8binternvl2-26binternvl2-40binternvl2-llama3-76b以下......
  • *算法训练(leetcode)第三十五天 | 121. 买卖股票的最佳时机、122. 买卖股票的最佳时机 I
    刷题记录*121.买卖股票的最佳时机贪心*动态规划122.买卖股票的最佳时机II贪心*动态规划*123.买卖股票的最佳时机III*121.买卖股票的最佳时机leetcode题目地址贪心找左侧最小值、右侧最大值(与最小值求差最大),求差即为最大利润。时间复杂度:......
  • Cuberite——低配mc服务器的最佳选择
    最近白嫖了一个1h1g的服务器,想拿它来开mc服务器,正当我用mcsmanager开服的时候,突然给我报了一条OutOfMemoryError下面就给大家介绍一下CubreiteCuberiteCuberiteisaMinecraft-compatiblemultiplayergameserverthatiswritteninC++anddesignedtobeefficientwith......
  • 代码随想录 day 41 买卖股票的最佳时机系列
    买卖股票的最佳时机买卖股票的最佳时机解题思路使用动态规划的思路解决,这类题目和之前做到过的所有动态规划相比有一定变化。在确定数组方面,这系列的题目都使用了二维数组来表示买卖股票的不同状态。在递归方面,本系列和小偷,背包等问题不同,它的状态递推关系也不是需要前两种系列......
  • 即使输出与参考不匹配,为什么 GEKKO 不提供最佳命令?
    以下内容与此问题相关:使用GEKKO的预测控制模型我正在尝试应用MPC将房间的温度保持在定义的范围内,但即使输出存在分歧,GEKKO也会给我空命令。我运行上一个问题中的更正代码:#Importlibraryimportnumpyasnpimportpandasaspdimporttimefromgekkoimpo......