当前位置: 首页 > news >正文

凸包(Convex Hull)

目录

1、前言

1.1什么是凸包

2、算法基础铺垫

2.1数学基础

2.1.1叉积

2.2数据结构基础

2.2.1栈

3、算法实现(C++)

3.1算法(Andrew)讲解

3.2代码复现


1、前言

1.1什么是凸包

给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有的点

2、算法基础铺垫

2.1数学基础

2.1.1叉积

对于两个空间向量,叉积定义为:

当纵坐标时,即当向量处于同一平面时,我们有:

此时,我们可以知道:

,向量共线

,向量在向量的逆时针区域内

,向量在向量的顺时针区域内

2.2数据结构基础

2.2.1栈

此处略

3、算法实现(C++)

3.1算法(Andrew)讲解


文字说明:

(1)将点集中的所有点按横坐标升序排列(横坐标相同时,按纵坐标升序排列)

(2)遍历排序后的点集以构建下凸壳:当栈中点数不少于 2 时,每新入一个点,都通过叉积回溯检查栈顶点,剔除凹点或共线点,直至完成下凸壳构建

(3)遍历点集以构建上凸壳:以下凸壳完成时的栈大小为界,当栈中点数超过下凸壳的点数时,每新入一个点,都通过叉积回溯检查栈顶点,剔除凹点或共线点,直至完成上凸壳构建


图片说明:

如下,为一个点集,其中每个点都涵盖两个参数——其横纵坐标值,即该点在平面的坐标

(1)根据各自横坐标进行排序

(2)将点1、点2入栈

(3)新入点3时,回溯时发现点2为凹点,于是将点2弹出,点3入栈

于是得到:

(4)新入点4,回溯检查,无误

(4)新入点5,回溯时发现点4为凹点,于是将点4弹出,点5入栈

于是得到:

继续回溯检查,发现点3为凹点,于是将点3弹出,点5入栈,得到:


【注】

我们以点集中的遍历顺序为依据把一个凸包分成两部分,即下凸壳和上凸壳

凸包部分遍历顺序
下凸壳从小到大
上凸壳从大到小

同理下凸壳,上凸壳的求解流程图如下:

(5)

(6)

(7)

(8)


该点集的完整凸包求解完毕

显然,栈中有个元素,则凸包上有个元素(将点1重复置于栈内)

显然,凸包周长为:

3.2代码复现

例题:【洛谷P2742】

代码:

#include<algorithm> #include<iostream> #include<iomanip> #include<utility> #include<cmath> #include<vector> #include<stack> using namespace std; stack<pair<double, double>> st; vector<pair<double, double>> point; bool Cross(pair<double, double> p1, pair<double, double> p2, pair<double, double> p3) { double cross = (p2.first - p1.first)* (p3.second - p1.second)- (p2.second - p1.second)* (p3.first - p1.first); return cross <= 0; } void Convex_Hull(int n) { sort(point.begin() + 1, point.end()); for (int i = 1; i <= n; ++i) { while (st.size() >= 2) { pair<double, double> Pa = st.top(); st.pop(); pair<double, double> Pb = st.top(); pair<double, double> S = point[i]; if (Cross(Pb, Pa, S)) continue; else { st.push(Pa); break; } } st.push(point[i]); } int tmp = st.size(); for (int i = n - 1; i >= 1; i--) { while (st.size() > tmp) { pair<double, double> Pa = st.top(); st.pop(); pair<double, double> Pb = st.top(); pair<double, double> S = point[i]; if (Cross(Pb, Pa, S)) continue; else { st.push(Pa); break; } } st.push(point[i]); } } double dis(double x1, double y1, double x2, double y2) { return sqrt(pow((x1 - x2), 2) + pow((y1 - y2), 2)); } int main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin >> n; double l = 0; double x; double y; point.emplace_back(0, 0); for (int i = 1; i <= n; i++) { cin >> x >> y; point.emplace_back(x, y); } Convex_Hull(n); while (st.size() > 1) { double x1 = st.top().first; double y1 = st.top().second; st.pop(); double x2 = st.top().first; double y2 = st.top().second; l += dis(x1, y1, x2, y2); } cout << fixed << setprecision(2) << l; return 0; }

3.3反思

(1)在 Andrew 单调链凸包算法中,栈内点集始终保持凸性单调性质,即从栈底到栈顶,任意连续三点均满足左转(凸)关系。当处理新点时,若当前栈顶的三个点构成非左转(凹或共线)关系,则弹出栈顶点;当首次检测到栈顶三点满足左转(凸)性质时,即可停止回溯并退出循环。

这是因为:

此前的回溯操作已保证栈内剩余部分仍为合法的凸性单调链;

新点与当前栈顶两点构成凸关系后,其与更下方的栈内点的转向关系必然也满足凸性,无需继续回溯。

while (st.size() >= 2) { pair<double, double> Pa = st.top(); st.pop(); pair<double, double> Pb = st.top(); pair<double, double> S = point[i]; if (Cross(Pb, Pa, S)) continue; else { st.push(Pa); break; } }

因此,算法仅需在首次检测到凸性成立时退出循环(break),即可保证后续栈内点集的凸性,无需回溯到底。

http://www.jsqmd.com/news/707068/

相关文章:

  • 机器学习数据预处理网格搜索优化实战
  • Letta Code:构建拥有长期记忆的AI编程伙伴,告别重复沟通
  • 第76篇:AI+物流与仓储自动化——分拣机器人、无人配送与智能调度系统(项目实战)
  • Pytorch基础——(3)神经网络工具箱
  • Phi-3-mini-4k-instruct-gguf效果展示:Chainlit前端实时流式输出+Markdown格式化响应截图
  • 从0到1集成FlyRefresh:Android开发者必备的下拉刷新解决方案
  • 2026年怎么选变压器生产厂家:变压器回收价格/变压器回收公司/变压器回收厂家/变压器回收多少钱一台/干式变压器厂家/选择指南 - 优质品牌商家
  • 2.6 应用容器:给应用套上的“现代化沙箱”
  • TVA检测技术在普通电子元器件领域的全维度解析(17)
  • 团体程序设计天梯赛竞赛题--登顶题【L3-043 门诊预约排队系统】
  • 南京邮电大学电装实习报告-2026版
  • 大学生就业信息管理|基于java+ vue大学生就业信息管理系统(源码+数据库+文档)
  • Qwen-Turbo-BF16部署教程:离线环境预下载模型权重与LoRA文件校验方案
  • AI项目环境管理利器:PyTorch 2.9云端镜像多实例使用攻略
  • 【Linux3】压缩解压缩,命令解释器,账户和组管理,文件系统权限
  • Arm A-profile架构TLB维护与内存管理机制解析
  • nlp_structbert_sentence-similarity_chinese-large效果展示:多领域中文文本相似度计算案例集
  • Python时间序列数据分析:从基础到实战
  • Qianfan-OCR在MobaXterm中的实践:远程服务器部署与中文环境调试
  • Phi-3.5-Mini-Instruct实战手册:系统提示词工程——从通用助手到领域专家
  • C++位图学习笔记
  • 【大白话说Java面试题】【Java基础篇】第8题:HashMap在计算元素下标时,为什么要进行二次hash
  • 线性表小回顾
  • Linux 0.11源码深度解析:kernel/chr_drv/tty_io.c —— 终端I/O的控制中枢与行规约引擎
  • Python新手在PyCharm写if总报错?5个坑90%人踩过,看完修复
  • C语言函数全解析
  • AI自主监测宠物健康,陪狗都不用自己来了!涂鸦Hey Tuya打造全屋智能“超级入口”
  • 快速上手:使用Clawdbot将星图平台Qwen3-VL接入飞书,实现智能问答
  • 【Linux从入门到精通】第17篇:日志系统——系统运行的黑匣子
  • 深度解析YOLOv11多光谱目标检测的技术实现与性能优化