【计算几何】凸包问题 (Convex Hull)

news/2024/9/28 1:07:30

【计算几何】凸包问题 (Convex Hull)

引言

凸多边形

凸多边形是指所有内角大小都在\([0,π]\)范围内的简单多边形

凸包

在平面上能包含所有给定点的最小凸多边形叫做凸包。

其定义为:对于给定集合 X,所有包含 X 的凸集的交集 S 被称为 X 的 凸包。

实际上可以理解为用一个橡皮筋包含住所有给定点的形态。

凸包用最小的周长围住了给定的所有点。如果一个凹多边形围住了所有的点,它的周长一定不是最小,如下图。根据三角不等式,凸多边形在周长上一定是最优的。

在这里插入图片描述

凸包的求法

主要介绍Graham扫描法

Graham Scan 算法求凸包

Graham Scan 算法是一种十分简单高效的二维凸包算法,能够在 \(O(nlogn)\)
的时间内找到凸包。

Graham Scan 算法的做法是先确定一个起点(一般是最左边的点和最右边的点),然后一个个点扫过去,如果新加入的点和之前已经找到的点所构成的 "壳" 凸性没有变化,就继续扫,否则就把已经找到的最后一个点删去,再比较凸性,直到凸性不发生变化。分别扫描上下两个 "壳",合并在一起,凸包就找到了。这么说很抽象,我们看图来解释:

在这里插入图片描述
在这里插入图片描述

先找 "下壳",上下其实是一样的。首先加入两个点 A 和 B。

然后插入第三个点 C,并计算 \(\vec{AB} \times \vec{BC}\)的向量积,却发现向量积系数小于(等于)0,也就是说\(\vec{BC}\)
\(\vec{AB}\)的顺时针方向上。

在这里插入图片描述

于是删去 B 点。

在这里插入图片描述

按照这样的方法依次扫描,找完 "下壳" 后,再找 "上壳"。


#include <algorithm>struct Point {double x, y;// 重载减法运算符,用于计算向量差Point operator-(Point& p) {Point t;t.x = x - p.x;t.y = y - p.y;return t;}// 计算向量叉积double cross(Point p) {return x * p.y - p.x * y;}
};// 比较函数,用于排序点
bool cmp(Point& p1, Point& p2) {if (p1.x != p2.x) return p1.x < p2.x;return p1.y < p2.y;
}Point point[1005];  // 无序点
int convex[1005];   // 保存组成凸包的点的下标
int n;              // 坐标系的无序点的个数// 获取凸包的函数
int GetConvexHull() {// 按照x坐标排序,如果x相同则按照y坐标排序sort(point, point + n, cmp);int temp;int total = 0;// 构建下凸包for (int i = 0; i < n; i++) {// 如果当前栈中至少有两个点,并且新点使得栈顶的两个点与新点形成的向量不满足逆时针方向while (total > 1 &&(point[convex[total - 1]] - point[convex[total - 2]]).cross(point[i] - point[convex[total - 1]]) <= 0)total--;  // 弹出栈顶点convex[total++] = i;  // 将当前点加入栈中}temp = total;  // 记录下凸包的点数// 构建上凸包for (int i = n - 2; i >= 0; i--) {// 如果当前栈中至少有两个点,并且新点使得栈顶的两个点与新点形成的向量不满足逆时针方向while (total > temp &&(point[convex[total - 1]] - point[convex[total - 2]]).cross(point[i] - point[convex[total - 1]]) <= 0)total--;  // 弹出栈顶点convex[total++] = i;  // 将当前点加入栈中}return total - 1;  // 返回组成凸包的点的个数,实际上多了一个,就是起点,所以组成凸包的点个数是 total - 1
}

代码解释

结构体 Point:

  • 包含两个成员变量 x 和 y,表示点的坐标。

  • 重载了减法运算符 operator-,用于计算两个点的向量差。

  • 定义了 cross 方法,用于计算两个向量的叉积。

比较函数 cmp:

  • 用于对点进行排序,首先按 x 坐标排序,如果 x 坐标相同则按 y 坐标排序。

全局变量:

  • point 数组存储无序点。

  • convex 数组存储组成凸包的点的下标。

  • n 表示无序点的个数。

函数 \(GetConvexHull\):

  • 首先对点进行排序。

  • 构建下凸包:从左到右遍历点,使用栈来维护凸包的点,确保每次新加入的点与栈顶的两个点形成的向量满足逆时针方向。

  • 构建上凸包:从右到左遍历点,使用栈来维护凸包的点,确保每次新加入的点与栈顶的两个点形成的向量满足逆时针方向。

  • 返回组成凸包的点的个数,注意实际点的个数是 total - 1,因为起点被重复计算了一次。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

2535. 数组元素和与数字和的绝对差

给你一个正整数数组 nums 。 元素和 是 nums 中的所有元素相加求和。 数字和 是 nums 中每一个元素的每一数位(重复数位需多次求和)相加求和。 返回 元素和 与 数字和 的绝对差。 注意:两个整数 x 和 y 的绝对差定义为 |x - y| 。 示例 1: 输入:nums = [1,15,6,3] 输出:9…

[34](CSP 集训)CSP-S 联训模拟 1

A 几何 重复若干次 -> 不能重叠,因此考虑直接暴力 DP 设 \(f_{i,j,k}\) 表示主串匹配到第 \(i\) 位(将前 \(i\) 位分别归为两类),其中 \(x\) 在重复了若干次后,又匹配到了第 \(j\) 位,\(y\) 在重复了若干次后,又匹配到了第 \(k\) 位 转移非常好写,枚举 \(i\),尝试把…

ShiftAddAug:基于乘法算子训练的最新无乘法网络方案 | CVPR24

不包含乘法的运算符,如移位和加法,因其与硬件的兼容性而日益受到重视。然而,采用这些运算符的神经网络(NNs)通常表现出比具有相同结构的传统NNs更低的准确性。ShiftAddAug利用成本较高的乘法来增强高效但功能较弱的无乘法运算符,从而在没有任何推理开销的情况下提高性能。…

ubuntu录屏转格式 webm转mp4

起因 想着将一些操作录屏记录下来。之前在win上面,使用EV录屏或者用CS(CamtasiaStudio)。这次用ubuntu,发现系统自带的录屏似乎就可以用,于是试了一下。操作确实很方便,但录屏生成的文件是.webm后缀,似乎要上传一些平台需要转格式。遂祭起AI大旗。 AI协助转格式 在Ubunt…

飞驰云联亮相”电子半导体数智化年会” 获”数据交换领域最佳厂商奖”

2024年9月20日,“2024第二届电子半导体/智能制造数智化年会暨品牌出海论坛”于上海隆重开幕,Ftrans飞驰云联作为国内领先的数据安全交换厂商,应邀携半导体全场景产品和解决方案亮相此次峰会。会上进行了“智象奖”评选,Ftrans飞驰云联凭借创新的技术以及优质的服务,荣获“…

智能同步,效率倍增:Ftrans文件自动化实时同步技术革新!

随着企业结构分散化,企业内部数据流转更加频繁,为了保证数据在不同平台和设备之间的一致性和可用性、保障数据的安全性并有效支撑业务开展,越来越多的企业需要将内部数据在多个数据中心之间、多台服务器之间、多云和本地间进行服务器文件自动化实时同步处理。通过同步软件,…

跨地域协作新篇章:异地传输文件的最优方案!

基于市场拓展、获取丰富资源、实现长期战略目标、分散运营风险等考量,企业会在多个城市或国家设立分支机构,用以覆盖更广泛的市场和客户群体,提高业务的可靠性和稳定性。企业在实现总分支机构之间异地传输文件时,会面临以下挑战: 1.管理难统一 不同业务部门、机构之间进行…

鸿蒙应用开发——Scroll/List组件无法触发滑动,检查子组件的高度是否被固定/是否内嵌了Tabs组件

鸿蒙应用开发——Scroll/List组件无法触发滑动,检查子组件的高度是否被固定/是否内嵌了Tabs组件鸿蒙应用开发——Scroll/List组件无法触发滑动 一、检查子组件的高度是否被固定 若Scroll/List组件的子组件的高度超出了Scroll/List组件高度则能够滚动,此时子组件的高度固定且不…