C-10 凸包

news2024/12/28 5:14:32

凸包

数学定义

  • 平面的一个子集S被称为是凸的,当且仅当对于任意两点A,B属于S,线段PS都完全属于S
  • 过于基础就不详细介绍了
    在这里插入图片描述

凸包的计算

  • github上找到了别人的代码,用4种方式实现了凸包的计算,把他放在这里
  • 链接地址https://github.com/MiguelVieira/ConvexHull2D
  • 先放这个代码的用法吧
int main() {
	vector<point> v = getPoints();
//1
	vector<point> h = quickHull(v);
	cout << "quickHull point count: " << h.size() << endl;
	print(h);
    
//2
	h = giftWrapping(v);
	cout << endl << "giftWrapping point count: " << h.size() << endl;
	print(h);
    
//3
	h = monotoneChain(v);
	cout << endl << "monotoneChain point count: " << h.size() << endl;
	print(h);
    
//4
	h = GrahamScan(v);
	cout << endl << "GrahamScan point count: " << h.size() << endl;
	print(h);
  • 这是具体的代码,直接写在一个头文件里,包含一下就能在程序里实现上面的诸多用法了


#include <algorithm>
#include <iostream>
#include <vector>
#include<random>
	using namespace std;
namespace ch{
	struct point {
		float x;
		float y;

		point(float xIn, float yIn) : x(xIn), y(yIn) { }
	};

	// The z-value of the cross product of segments 
	// (a, b) and (a, c). Positive means c is ccw
	// from (a, b), negative cw. Zero means its collinear.
	float ccw(const point& a, const point& b, const point& c) {
		return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
	}

	// Returns true if a is lexicographically before b.
	bool isLeftOf(const point& a, const point& b) {
		return (a.x < b.x || (a.x == b.x && a.y < b.y));
	}

	// Used to sort points in ccw order about a pivot.
	struct ccwSorter {
		const point& pivot;

		ccwSorter(const point& inPivot) : pivot(inPivot) { }

		bool operator()(const point& a, const point& b) {
			return ccw(pivot, a, b) < 0;
		}
	};

	// The length of segment (a, b).
	float len(const point& a, const point& b) {
		return sqrt((b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y));
	}

	// The unsigned distance of p from segment (a, b).
	float dist(const point& a, const point& b, const point& p) {
		return fabs((b.x - a.x) * (a.y - p.y) - (b.y - a.y) * (a.x - p.x)) / len(a, b);
	}

	// Returns the index of the farthest point from segment (a, b).
	size_t getFarthest(const point& a, const point& b, const vector<point>& v) {
		size_t idxMax = 0;
		float distMax = dist(a, b, v[idxMax]);

		for (size_t i = 1; i < v.size(); ++i) {
			float distCurr = dist(a, b, v[i]);
			if (distCurr > distMax) {
				idxMax = i;
				distMax = distCurr;
			}
		}

		return idxMax;
	}


	// The gift-wrapping algorithm for convex hull.
	// https://en.wikipedia.org/wiki/Gift_wrapping_algorithm
	vector<point> giftWrapping(vector<point> v) {
		// Move the leftmost point to the beginning of our vector.
		// It will be the first point in our convext hull.
		swap(v[0], *min_element(v.begin(), v.end(), isLeftOf));

		vector<point> hull;
		// Repeatedly find the first ccw point from our last hull point
		// and put it at the front of our array. 
		// Stop when we see our first point again.
		do {
			hull.push_back(v[0]);
			swap(v[0], *min_element(v.begin() + 1, v.end(), ccwSorter(v[0])));
		} while (v[0].x != hull[0].x && v[0].y != hull[0].y);

		return hull;
	}


	// The Graham scan algorithm for convex hull.
	// https://en.wikipedia.org/wiki/Graham_scan
	vector<point> GrahamScan(vector<point> v) {
		// Put our leftmost point at index 0
		swap(v[0], *min_element(v.begin(), v.end(), isLeftOf));

		// Sort the rest of the points in counter-clockwise order
		// from our leftmost point.
		sort(v.begin() + 1, v.end(), ccwSorter(v[0]));

		// Add our first three points to the hull.
		vector<point> hull;
		auto it = v.begin();
		hull.push_back(*it++);
		hull.push_back(*it++);
		hull.push_back(*it++);

		while (it != v.end()) {
			// Pop off any points that make a convex angle with *it
			while (ccw(*(hull.rbegin() + 1), *(hull.rbegin()), *it) >= 0) {
				hull.pop_back();
			}
			hull.push_back(*it++);
		}

		return hull;
	}


	// The monotone chain algorithm for convex hull.
	vector<point> monotoneChain(vector<point> v) {
		// Sort our points in lexicographic order.
		sort(v.begin(), v.end(), isLeftOf);

		// Find the lower half of the convex hull.
		vector<point> lower;
		for (auto it = v.begin(); it != v.end(); ++it) {
			// Pop off any points that make a convex angle with *it
			while (lower.size() >= 2 && ccw(*(lower.rbegin() + 1), *(lower.rbegin()), *it) >= 0) {
				lower.pop_back();
			}
			lower.push_back(*it);
		}

		// Find the upper half of the convex hull.
		vector<point> upper;
		for (auto it = v.rbegin(); it != v.rend(); ++it) {
			// Pop off any points that make a convex angle with *it
			while (upper.size() >= 2 && ccw(*(upper.rbegin() + 1), *(upper.rbegin()), *it) >= 0) {
				upper.pop_back();
			}
			upper.push_back(*it);
		}

		vector<point> hull;
		hull.insert(hull.end(), lower.begin(), lower.end());
		// Both hulls include both endpoints, so leave them out when we 
		// append the upper hull.
		hull.insert(hull.end(), upper.begin() + 1, upper.end() - 1);
		return hull;
	}


	// Recursive call of the quickhull algorithm.
	void quickHull(const vector<point>& v, const point& a, const point& b,
		vector<point>& hull) {
		if (v.empty()) {
			return;
		}

		point f = v[getFarthest(a, b, v)];

		// Collect points to the left of segment (a, f)
		vector<point> left;
		for (auto p : v) {
			if (ccw(a, f, p) > 0) {
				left.push_back(p);
			}
		}
		quickHull(left, a, f, hull);

		// Add f to the hull
		hull.push_back(f);

		// Collect points to the left of segment (f, b)
		vector<point> right;
		for (auto p : v) {
			if (ccw(f, b, p) > 0) {
				right.push_back(p);
			}
		}
		quickHull(right, f, b, hull);
	}

	// QuickHull algorithm. 
	// https://en.wikipedia.org/wiki/QuickHull
	vector<point> quickHull(const vector<point>& v) {
		vector<point> hull;

		// Start with the leftmost and rightmost points.
		point a = *min_element(v.begin(), v.end(), isLeftOf);
		point b = *max_element(v.begin(), v.end(), isLeftOf);

		// Split the points on either side of segment (a, b)
		vector<point> left, right;
		for (auto p : v) {
			ccw(a, b, p) > 0 ? left.push_back(p) : right.push_back(p);
		}

		// Be careful to add points to the hull
		// in the correct order. Add our leftmost point.
		hull.push_back(a);

		// Add hull points from the left (top)
		quickHull(left, a, b, hull);

		// Add our rightmost point
		hull.push_back(b);

		// Add hull points from the right (bottom)
		quickHull(right, b, a, hull);

		return hull;
	}

	vector<point> getPoints() {
		vector<point> v;
		std::default_random_engine e(std::random_device{}());
		std::uniform_real_distribution<double> dist_x(0.05, 0.95);
		std::uniform_real_distribution<double> dist_y(0.05, 0.95);


		for (int i = 0; i < 30; ++i) {
			v.push_back(point(dist_x(e), dist_y(e)));
		}

		return v;
	}
}

可视化实现

这个exe小程序我放在主页了,大家可以免费下载,之后会创建一个仓库把代码公开出来,大家就可以在我的基础上实现更多的几何算法。
请添加图片描述

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

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

相关文章

六、数据可视化—Wordcloud词云(爬虫及数据可视化)

六、数据可视化—Wordcloud词云&#xff08;爬虫及数据可视化&#xff09; 也是一个应用程序 http://amueller.github.io/word_cloud/ Wordcloud词云&#xff0c;在一些知乎&#xff0c;论坛等有这样一些东西&#xff0c;要么做封面&#xff0c;要么做讲解&#xff0c;进行分析…

Echarts 实现数据可视化

Echarts 简介 Echarts 是一个开源的、免费的、成熟的、商业级图表可视化框架&#xff0c;是 Apache 开源社区的顶级项目之一&#xff0c;也是国内使用最多和最为广泛的可视化图表框架之一。 数据可视化图表框架并没有一个统一的行业标准&#xff0c;比较常见的有 D3、Highchart…

电子设备常用的胶水有哪些?

目录 1、502胶水 2、703胶水 3、704胶水 4、AB胶 5、红胶 6、Underfill 7、导电胶 8、UV胶 9、热熔胶 10、环氧树脂胶 11、硅酮胶 12、聚氨酯胶 13、丙烯酸胶 14、丁基胶 1、502胶水 502胶水&#xff0c;也被称为瞬间胶或快干胶&#xff0c;是一种非常常见的粘合…

如何下载Github上项目中的一个目录或几个文件

目录 问题的由来 GitZip for Github插件 Edge中插件的安装 Chome中插件的安装 插件的使用 Github授权 文件下载 问题的由来 经常使用Github的可能都会有这样的需求&#xff0c;有的时候一个仓库好几个GB&#xff0c;但是感兴趣的只是某个目录下的文件。Git没有单独下载…

CTFShow的RE题(四)

真的是签到 给的是无后缀的 zip 文件&#xff0c;解压发现需要密码&#xff0c;也没有提示&#xff0c;猜测可能是 zip 伪加密 &#xff08;走错厂了吧&#xff09; zip是否加密 首先就是看开头的6 &#xff0c;7byte&#xff0c;和中间 01 02 后的 5 &#xff0c;6byte 成功解…

如何做一个透明度渐现且向上位移逐行出现的文字效果

前言 在这个夜黑风高的夜晚&#xff0c;你的眼睛已经开始有些疲惫。你的手指在键盘上轻轻地敲击着&#xff0c;仿佛在弹奏一首无声的夜曲。你的思绪在代码的海洋中飘荡&#xff0c;寻找着最后一行需要完成的代码。就在这时&#xff0c;你的老板走了过来&#xff0c;他的脸上带…

简过网:事业单位编制有哪几种类型,你都知道吗?

近几年来&#xff0c;随着考编、考公热&#xff0c;越来越多的朋友都有考编的想法&#xff0c;尤其是刚毕业的大学生&#xff0c;但是很多朋友对于事业单位编制有不清楚的地方&#xff0c;比如到底哪些属于事业单位的范围&#xff0c;事业单位编制分为哪些类型&#xff1f;今天…

解决:Android Studio 突然打不开!提示Failed to create JVM:error code -1

Android studio1.5 一直用得好好的&#xff0c;突然有一天打不开&#xff0c;并提示&#xff1a; 可是系统配置中&#xff0c;java的配置也是正常的。 解决方法&#xff1a; 修改安装目录下的studio64.exe.vmoptions 文件 直接将文件内容改成&#xff1a; -Xms128m -Xmx512m…

【活动行】参与上海两场线下活动,教育生态行业赛总决赛活动和WAIC人工智能大会活动 - 上海活动总结

目录 背景决赛最后一公里领域范围 决赛作品AI智教相机辅导老师Copilot辅导老师Copilot雅思写作竞技场 优秀作品总结 背景 决赛 百度发起的千帆杯教育生态行业赛于2024年7月4日进行线下决赛&#xff0c;博主虽然没能进入决赛&#xff0c;但也非常荣幸能够以嘉宾身份到现场给进…

213.贪心算法:跳跃游戏||(力扣)

class Solution { public:int jump(vector<int>& nums) {if (nums.size() 1) return 0; // 如果数组长度为1&#xff0c;已经在终点&#xff0c;不需要跳跃int cur 0; // 当前跳跃能到达的最远位置int flag 0; // 记录跳跃次数int next 0; // 下一次跳跃能到…

软件设计之Java入门视频(13)

软件设计之Java入门视频(13) 视频教程来自B站尚硅谷&#xff1a; 尚硅谷Java入门视频教程&#xff0c;宋红康java基础视频 相关文件资料&#xff08;百度网盘&#xff09; 提取密码&#xff1a;8op3 idea 下载可以关注 软件管家 公众号 学习内容&#xff1a; 该视频共分为1-7…

2024年【低压电工】考试题库及低压电工考试总结

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年低压电工考试题库为正在备考低压电工操作证的学员准备的理论考试专题&#xff0c;每个月更新的低压电工考试总结祝您顺利通过低压电工考试。 1、【单选题】PE线或PEN线上除工作接地外其他接地点的再次接地称为(…

通过Vxlan实现数据中心互联有感

随着企业的发展&#xff0c;为满足跨地域运营、用户接入、异地灾备等场景&#xff0c;越来越多的企业通常在多地域部署多个数据中心。 数据中心互联DCl(Data Center Interconnection)是不同数据中心VM之间互相通信的一种解决方案使用VXLAN、BGP EVPN等技术&#xff0c;使数据中…

RoPE 旋转位置编码,详细解释(下)NLP 面试的女生彻底说明白了

RoPE 旋转位置编码&#xff0c;详细解释&#xff08;下&#xff09;NLP 面试的女生彻底说明白了 原创 看图学 看图学 2024年07月01日 07:55 北京 书接上文&#xff0c;上文见&#xff1a;这么解释 RoPE 旋转位置编码&#xff0c;女朋友睁大了双眼&#xff08;上&#xff09; …

12种增强Python代码的函数式编程技术

前言 什么是函数式编程&#xff1f; 一句话总结&#xff1a;函数式编程(functional programming)是一种编程范式&#xff0c;之外还有面向对象&#xff08;OOP&#xff09;、面向过程、逻辑式编程等。 函数式编程是一种高度抽象的编程范式&#xff0c;它倡导使用纯函数&#x…

【计算机网络】物理层(作业)

1、若信道在无噪声情况下的极限数据传输速率不小于信噪比为30dB 条件下的极限数据传输速率&#xff0c;则信号状态数至少是&#xff08;D&#xff09;。 A. 4B. 16C. 8D. 32 解析&#xff1a;可用奈奎斯特采样定理计算无噪声情况下的极限数据传输速率&#xff0c;用香农第二定…

Aqara 发布多款智能照明新品,引领空间智能新时代

7月8日&#xff0c;全球 IoT 独角兽品牌 Aqara 以“光&#xff0c;重塑空间想象”为主题&#xff0c;举办了线上智能照明新品沟通会。 会上&#xff0c;Aqara 正式发布一系列引领行业的智能照明新品&#xff0c;包括银河系列轨道灯 V1 以及繁星系列妙控旋钮 V1 等&#xff0c;…

Leetcode—97. 交错字符串【中等】

2024每日刷题&#xff08;140&#xff09; Leetcode—97. 交错字符串 2d动规实现代码 class Solution { public:bool isInterleave(string s1, string s2, string s3) {int m s1.length();int n s2.length();int len s3.length();if(m n ! len) {return false;}vector<…

metersphere链接腾讯邮箱步骤

1、打开腾讯邮箱生成授权码 路径&#xff1a;设置-账户-账户安全 生成的授权码只会展示1次&#xff0c;注意保存 2、在系统设置-系统参数设置-邮件设置填写授权码和SMTP信息 SMTP信息在邮箱的客户端设置中可以获取到对应的信息 3、信息填写完后&#xff0c;可以测试连接&…

XDMA原理学习(1)——DMA技术详解

目录 一、什么是DMA&#xff1f;为什么需要DMA&#xff1f; 二、DMA分类 2.1 Block DMA 2.2 Scatter-Gather DMA 2.3 Ring buffer DMA 三、实际案例 3.1 STM32微处理器 3.1.1 Block DMA 3.1.2 Scatter-Gather DMA 3.1.3 使用场景举例&#xff1a; 3.1.4 配置与实现 …