学习凸包(五):卷包裹算法--兼解POJ1113(JAVA)

 一种形象的理解是:我们用一根麻绳绑住一个外面的钉子(点), 然后拉着麻绳绕所有钉子一圈,这个麻绳最后也构成了点集的凸包。


这就是卷包裹法(Gift Wrapping)的思路
卷包裹算法从一个必然在凸包上的点开始向着一个方向依次选择最外侧的点,当回到最初的点时,所选出的点集就是所要求的凸包。这里还有两个问题不是很清楚:

1.怎么确定一个肯定在凸包上的点?
这个问题很好解决,取一个最左边的也就是横坐标最小的点(或最下边的点,纵坐标最小的),如果有多个这样的点, 就取这些点里纵坐标(横坐标)最小的。


2.如何确定下一个点(即最外侧的点)?
需要利用向量的叉积来解决这个问题



比如现在我们卷包裹卷到J点我们要选取一个最外侧的点,当然比较红色的到角可以直接得到最外侧的点,不过不方便,我们可以考虑那个蓝色的到角,利用向量 我们可以比较哪个点"更外侧"。比如点K和点I,我们利用向量JK乘以向量JI得到一个数,这个数应该是负数,说明I比K更外侧。两个向量的比较具有传递性,所以我们可以像N个数里取最大的数一样取出最外侧的。

遍历所有点,每个点都和现有最外侧的点比较,得到新的最外侧的点。

至此两个问题都得以解决 我们可以写出满足一般要求的卷包裹算法了,不过还遗留有一个问题 就是处理共线的问题。有时候我们需要凸包边上的点也考虑到,有时候却需要去掉这些点,我们通常称在凸包顶点处的点为极点,如果我们只要求保留极点而去除在边上的点,我们只需在取外侧的点的时候,碰到共线的点取最远的,相反 如果我们要保留所有在边上的点我们只需要在共线的点中取最近的。这样整个卷包裹法终于完成了:

下面是卷包裹算法解poj 1113的AC代码:
关于POJ 1113请参看:http://128kj.iteye.com/blog/1748635

Java代码 复制代码 收藏代码
  1. import java.util.*;
  2. class point implements Comparable {//平面上的一个点
  3. double x;
  4. double y;
  5. public int compareTo(Object o) {//按y升序排列,y相同按x升序
  6. point b=(point)o;
  7. if(this.y>b.y) return 1;
  8. else if(this.y==b.y ){
  9. if(this.x>b.x) return 1;
  10. else if(this.x==b.x) return 0;
  11. else return -1;
  12. }
  13. else return -1;
  14. }
  15. }   
posted on 2013-02-20 20:28  蜜雪薇琪  阅读(358)  评论(0编辑  收藏  举报