AcWing算法进阶课 计算几何 凸包
什么是凸包
假设平面上现在有若干个点,现在我们过某些点做一个多边形,是这个多边形能够将所有点都包含起来【在多边形边上也算】。当这个多边形是一个凸多边形的时候,我们称它问凸包。
可以想象为给这些点外面箍上一个橡皮筋。
解决凸包问题的算法
暴力
时间复杂度为O(n^3)
思路:先确定两个点,然后枚举剩下的其他所有点,如果其他所有点都在这条直线的同一侧,则这两个点是凸包上的点,否则就不是。
解决:
1.枚举点对(将所有的点两两配对)组成的直线,对于每条直线,检查是否剩下的(n-2)个点是否在直线的同侧。
假设枚举的点对是a和b,而新的点是c,那么我们只需要判断他们的叉积是否同时为正或者同时为负就OK了。
Andrew算法
时间复杂度
O(nlogn)
【时间主要是在对坐标的快排上】Andrew算法:Andrew算法是对Graham扫描法的改进。-
原理:
利用夹角,让整个图形保持左转。先将最左边的前两个点加入栈中,每次加入新点时判断是否左拐(叉积大于0),如果是就将新点直接加入;如果不是,就弹出栈顶,直到左拐,将新点加入栈中。【注意,栈中要保证至少有一个元素,也就是top>=2的时候才可以弹出栈顶】第一遍找的都是y小的点,也就是下凸包,上面没有,然后我们反着再来一遍。
流程:
1.将所有点进行快排,以x为第一关键字,y为第二关键字升序排序
2.先从左至右维护凸包的下半部分,然后再从右至左谓语上半部分。
3.将第一个点放入栈中,【这个点一定时凸包的最左边的点了,是不会清理掉的】,然后在将第二个点放入栈中。当栈中元素大于等于2的时候,就要判断栈顶元素是否还要保留。
如果新点在栈顶元素和次栈顶元素所组成的直线的右侧,那么,直接将新点加入栈中。
如果新点在栈顶元素和次栈顶元素所组成的直线的左侧,那么,将栈顶元素不断弹出,直到新点的位置出现在栈顶元素与次栈顶元素所在直线的右侧结束。
那么,我们这个过程,是从左往右走的,而且每次找的点都是在当前直线的右侧,也就是直线的下方向,那么我们得到的凸包就是我们的下半部分。
代码: