凸包, 概念

凸包

通常上讲
平面上有很多的点, 用一个 皮筋 圈住 这所有的点, 此时这个 皮筋, 就是 这些点的 凸包

数学上讲
性质1: 凸包上, 任何一条边 他所在的直线 即为L, 则所有的点 都在直线L 的 同一侧
在这里插入图片描述

比如以凸包上的 AB边 为例, 所有的点: (要么在AB直线上) (要么都在同一侧比如以A->B这个方向来看, 都在该向量的 右侧)


性质2 (重点):

  • 由于凸包是一个环, 存在(顺时针 和 逆时针) 两个方向, 不妨先统一规定下 方向, 比如以 顺时针来看.

  • 凸包上 任意连续的3个点 ABC, 由于是顺时针, 我们看 A -> B 这个方向的 向量
    你让这个向量, 以 A点 为中心 顺时针的旋转, 直到他 遇到 第一个C, 则, 该点C, 就是 继AB后 凸包上的 下一个点


性质3: 还是以 顺时针为例

  • 对于凸包上的 任意一个点 A (即, 已知, A点 是凸包上的点), 设B点是 A点 顺时针 的 下一个点. 记其他的(除了AB点) 的所有点 为Set集合
    记: A -> B向量 为 vec1, A -> Set 所构成的 所有向量 为 vec2
    则一定有: vec1 * vec2 (叉积) <= 0
  • 从上图可以看出, 已知A点 是凸包上的点
    假设C点, 是A点 顺时针的 下一个点;
    但是, 存在B点, 使得: A->C * A->B 的叉积 > 0; 说明: C点, 不是A点的 下一点
    A->B向量 * A->other向量 的叉积 均是 <= 0 的. 说明: B点, 是A点的 下一个凸包上的点

这个性质, 是我们 获取凸包 (即获取凸包上所有的点), 算法的 核心依据.
因为这个性质 告诉我们, 如何通过 一个 凸包上的点, 找到 他的 下一个凸包上的点.


算法1 O(n * m)

统一以: 顺时针 为方向

先获取一个凸包上的点Start
O(n)遍历, 找到 对{x,y}sort的 最小/最大的点 无需sort, O(n)cmp即可
这个点, 可以证明, 他一定是凸包上的, 因为他是 极值点;

已知一个凸包上的点A, 如何得到他的下一个点B

Start点;  ' 也就是上面的, 凸包的Start点 '
A点;  ' 已经得到的凸包上的 顺时针的 最后一个点 '
B点 = 任意一个 {
   非A}的点
FOR( C : 所有点){
   
	if( {
   A->C向量} 是在 {
   A->B向量} 左侧){
   
		B = C;   ' 更新B '
	}
}
if( B == Start){
     ' 这里很重要, 说明 又回到起点了 '
	break; 
}

具体代码

__VE< int> convex;
convex.clear();
{
   
	int j = 0;
	__FOR(i, 1, n-1, 1){
   
		if( -1 == Db_cmp( points[i].x, points[j].x, eps)){
   
			j = i;
		}
		else if( 0 == Db_cmp( points[i].x, points[j].x, eps) 
  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值