凸包问题 分治法求解

本文介绍了如何使用分治法解决凸包问题。通过将点集按x坐标排序,选取最左和最右的点作为分割线,然后找出分割线两侧的最远点,进一步划分子问题并递归求解。最终,递归边界条件是点集合小于3,此时所有点都在凸包上。递归过程中,根据子问题的上半部分或下半部分确定后续递归的区域。
摘要由CSDN通过智能技术生成

问题介绍

给定平面上一些点的集合,找到一些点,使得这些点形成一个凸的包围,围住所有的点,如图
在这里插入图片描述

思路

采用分治法,将点集合一分为二,整体的凸包问题可以分为【求上半部分的凸包】+【求下半部分的凸包】

分策略

将集合一分为二的策略是:将点按照x升序排序,x相同则按y升序,然后选取0和最后一个下标,以这两点做一条直线,这两点一定是最左边和最右边的,我们用 pa 和 pb 表示这两点
在这里插入图片描述

为子问题求解划分范围

已经将集合一分为二了,那么子问题的求解区间该怎么划定呢?

遍历所有的点

  • 找到在【直线pa pb】上方,距离【直线pa pb】最远的点 pmax
  • 找到在【直线pa pb】下方,距离【直线pa pb】最远的点 pmin

最远距离表示

这个距离我们可以用他们三点组成的三角形的面积来表示,这个行列式可以求解,值得注意的是,p1一定是在p2左边,p1,p2组成直线,p3是我们要判断的那个点

  • 最后得出的值大于0,说明 p3 在【直线 p1 p2】上方
  • 最后得出的值小于0,说明 p3 在【直线 p1 p2】下方
  • 最后得出的值等于0,说明 p3 在【直线 p1 p2】上
    在这里插入图片描述
    我们找到在【直线pa pb】上方,距离【直线pa pb】最远的点 pmax,找到在【直线pa pb】下方,距离【直线pa pb】最远的点 pmin,将 pa, pb, pmax, pmin 连起来,得到如下的图
    在这里插入图片描述
    把 【直线 pa pmax 】上方的点作为下一次查找的集合 s1
    把 【直线 pmax pb 】上方的点作为下一次查找的集合 s2
    把 【直线 pa pmin 】下方的点作为下一次查找的集合 s3
    把 【直线 pmin pb 】下方的点作为下一次查找的集合 s4

在这里插入图片描述

分别递归四个区域点的集合,值得注意的是

使用points数组存储点
使用vis数组,表示下标为 i 的点是不是凸包上的点,vis[i] = 1则是

  • 递归的边界情况,点集合的数目小于3,说明所有点都在凸包上,vis 置 1
  • 在直线上的点,也要加入下一次的点的集合
  • 如果递归的是上半部分的集合,那么之后的所有递归都只用针对上半部分,递归 s1 s2
  • 如果递归的是下半部分的集合,那么之后所有的递归都只用针对下半部分,递归 s3 s4
  • 如果递归的是全体集合(只有第一次递归会发送这个情况),需要同时递归上下部分,即同时递归 s1 s2 s3 s4

代码

输入:

12
1 1
1 2
2 0
2 1
2 3
3 1
3 3
4 0
4 2
5 1
5 4
6 2

输出

(1, 1)
(1, 2)
(2, 0)
(2, 3)
(4, 0)
(5, 1)
(5, 4)
(6, 2)
#include <bits/stdc++.h>

using namespace std;

// 结构定义 
typedef struct p
{
   
	int x
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值