首先,什么是凸包?
假设平面上有p0~p12共13个点,过某些点作一个多边形,使这个多边形能把所有点都“包”起来。当这个多边形是凸多边形的时候,我们就叫它“凸包”。如下图:
然后,什么是凸包问题?
我们把这些点放在二维坐标系里面,那么每个点都能用 (x,y) 来表示。
现给出点的数目13,和各个点的坐标。求构成凸包的点?
时间复杂度:O(n³)。
思路:两点确定一条直线,如果剩余的其它点都在这条直线的同一侧,则这两个点是凸包上的点,否则就不是。
步骤:
如何判断一个点 p3 是在直线 p1p2 的左边还是右边呢?(坐标:p1(x1,y1),p2(x2,y2),p3(x3,y3))
当上式结果为正时,p3在直线 p1p2 的左侧;当结果为负时,p3在直线 p1p2 的右边。
时间复杂度:O(n㏒n)。
思路:应用分治法思想,把一个大问题分成几个结构相同的子问题,把子问题再分成几个更小的子问题……。然后我们就能用递归的方法,分别求这些子问题的解。最后把每个子问题的解“组装”成原来大问题的解。
步骤:
然而怎么求距离某直线最远的点呢?我们还是用到解一中的公式:
设有一个点 P3 和直线 P1P2 。(坐标:p1(x1,y1),p2(x2,y2),p3(x3,y3))
对上式的结果取绝对值,绝对值越大,则距离直线越远。
注意:在步骤一,如果横坐标最小的点不止一个,那么这几个点都是凸包上的点,此时上包和下包的划分就有点不同了,需要注意。
时间复杂度:O(nH)。(其中 n 是点的总个数,H 是凸包上的点的个数)
思路:
注意:
时间复杂度:O(n㏒n)
思路:Graham扫描的思想和Jarris步进法类似,也是先找到凸包上的一个点,然后从那个点开始按逆时针方向逐个找凸包上的点,但它不是利用夹角。
步骤:
最后,栈中的元素就是凸包上的点了。
以下为用Graham扫描法动态求解的过程:
3、Melkman算法
首先要说的是:很多人都认为这个是最好的算法。这个算法可以在个点有序的前提下,每次获得一个点就可以将
先前的凸包改造成新的凸包,因此,这个是一个在线算法,它有着其他算法无法比拟的优势。1987年Melkman提出的
的凸包算法,它不再使用堆栈了,转而使用双向表,这为凸包算法的历史掀开了崭新的一夜。
具体实现我就不说了,相信看过上面几句话的,现在都已经忍不住要学习了。
今天看了一下午《算法艺术》和网上的一些资料,终于又有了一些理解,那就补充一下吧。之前都是模模糊糊的,现
在明白了,可能我现在理解的还是错误的,但是我还是要说出来:
melkman是用来求简单多边形的凸包算法,可以在线性时间求出最小凸包。而其他几种则可以求点集的凸包的算法。
如果要用Melkman算法来求点集的凸包,那么首先也是要排序的,通过排序可以形成一个简单的多边形,然后才可以
在线性的时间求出最小凸包。
所以最终得到的结论是:求点集的凸包,时间复杂度的底线是O(nlogn)。
最后讨论一下共线的问题:
假设有这么几个点
0 0
0 1
0 2
2 2
1 1
和这几个点
1 1
2 2
3 3
4 4
对于上面的两组数据,如果用卷包裹算法和Graham-Scan的极角排序法做,要求只输出凸包上的定点,会出现什么样
的问题??
如果用Graham-Scan的水平序来写,会不会出现同样的问题??
大家可以好好想想!!!!
还有很多凸包方面的算法,比如Jarvis步进法、增量、溶解、QuickHull等,这些多用于数学中,实践意义不大,所以
就不说了。有兴趣了解凸包算法的发展史,可以看看蓝点大神的《漫话二维凸包》。