软件构造Lab1:凸包问题之Gift Wrapping礼品包装算法

凸包问题:Gift Wrapping算法

凸包问题

凸包(Convex Hull)是一个计算几何(图形学)中的概念。简而言之,就是给定平面点集,找出该点集中最外圈的点构成凸多边形,使得该平面点集中所有的点都在该凸多边形内或该多边形边上。
正如上图所示,红色圈圈部分就是该平面点集的凸包。

凸包问题算法

凸包问题的解法一般有如下几种:
穷举法(蛮力法) O(n3)
分治法 O(nlogn)
Graham扫描法 O(nlogn)
jarvis步进法 O(nH)(H是凸包上点的个数)
Gift Wrapping礼品包装算法 O(nlogn)
关于前五种算法,下面这个博客已经写的很清晰了:
https://blog.csdn.net/baningtao1470/article/details/101077108?utm_source=app
我再记录一下Gift Wrapping算法。

Gift Wrapping算法

基本思路:
先确定一个肯定在凸包上的点P0,然后由此出发寻找下一个凸包上的点P1,直到确定凸包上的点是P0为止。
可以把这个过程形象化的理解为小时候往钉子板上圈皮筋的过程,先把皮筋固定在一个钉子上,然后再绕一个钉子,直到最后把皮筋绑在最开始固定的那个钉子上,也就形成了一个圈。
第一:怎么确定一个必在凸包上的点?
可以想象,在该平面点集中最远的点必在凸包上。怎么去想这个最远,可以是最上,可以是最下,也可以是最左,也可以是最右,我的实现过程选择的是最左下,只需要对平面点集遍历一遍,找到横坐标最小的那个点,如果横坐标相等,那么就选择纵坐标较小的即可。
第二,怎么确定由已知点确定下一个点?
可以利用极角,也可以利用向量的叉乘来做。我们去观察下一个点的特点:假如以已知点为极坐标原点,那么下一个点则是极角最小的那个点。
接下来考虑怎么求极角,这就不细说了,高中数学知识,下面有代码实现,假设当前点(x1,y1),考察点(x2,y2),求cos,求sin,求tan,最后在用arc就能知道角度,我用的是Matn.atan(),要注意的是记得根据点所在的象限分类讨论。
第三,如果由共线的情况,那么这些共线的点的极角相同,该怎么处理?
这要看你需要求的是最小凸包还是最大凸包了,如果是最小凸包,那么就选这些点中与已知点距离最大的那一个;如果是最大凸包,那么就选与已知点距离最小的那一个。我在实现的时候,用了一个动态栈来保存可供选择的点:如果这个找到了一个角度更小的点,清空栈中所有的内容,再将该点放入栈顶;如果角度相等,那么直接入栈。这样如果最后,栈中只有一个元素,那么就是下一个凸包中的点;如果栈中有多个,则这些点共线,再比较距离即可。我觉得这样还挺好


    /*Calculate angle 
    a:definite point
    b:investigated point
    if this point is definite point,return -1,as a sign
    */
    public static double calculateConvexHullAngle(Point a,Point b) {
     double cosSign = -2;
     double sinSign = -2;
     double angle = 0;
  cosSign = b.x()-a.x();
  sinSign = b.y()-a.y(); 
  if(cosSign>0 && sinSign>=0)
   angle = Math.toDegrees(Math.atan(sinSign/cosSign));
  else if((cosSign<=0 && sinSign>0)||(cosSign<0 && sinSign<=0))
   angle = Math.toDegrees(Math.atan(sinSign/cosSign))+180;
  else if(cosSign>0 && sinSign<0)
   angle = Math.toDegrees(Math.atan(sinSign/cosSign))+360;
  else if(cosSign==0 && sinSign==0) 
   angle = -1;
  return angle;
    }
  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值