前言
画乃我思所欲,非我见所得。
几何算法常常出现在计算机图形学,大规模集成电路设计等方面,常常需要分析平面内点、线段、直线的关系,而其算法呢大多用到了归纳,分治等算法的思想。
几何算法举例
1.判断点是否在多边形内部
判断p是否在多边形内部?
从p连一条到多边形外部的点的直线
看与所有多边形的边相交几次
若为奇数
则在内部
如何找外部的点?
找一个点x值比多边形的所有点x值都大
2.构造多边形
平面内给n个点,怎么构造一个多边形
(1)
造一个圆包含多边形的所有点
然后从圆心绕一圈按顺序连接所有点
这就是个多边形
(2)
选择多边形x,y都最小的那个点
然后整个图就在1,2象限了
这样从角度的小到大连接所有点,就是多边形
3.凸包算法
寻找n个点的凸包
(1)
归纳
假设我们可以找到n-1个点的凸包
加入第n点
要么在凸包中,不用操作,
检测是否在凸包中
前面判断点是否在多边形中
O(n)
要么不在凸包中
要拓展凸包
删去原来在边上,现在在里面的点
遍历
支撑线:vn 与 vi vj 的直线分别于x轴角度是最大和最小
然后删点
T(n) = T(n - 1) + O(n)
O(n*n)
(2)
优化
礼物包裹算法
从一个点一个一个往过包
就像纸包红薯
先折一次,再折
就是第一个点,第二个点
第三个点
1,2向量与2,3向量角度最小
就是凸包
每个点需要与所有点计算角度
O(n * n)
(3)
优化
Graham扫描算法
选最右下角的点a
排序-每个点与a直线与x轴角度大小
从一个点往下找
排序后1,2点入栈
新加入3的与栈顶两元素比较
若向量旋转方向逆
就入栈
若顺
就栈顶元素出栈
循环
3 与栈顶两元素再比
这样排序O(nlogn)
每个点回溯
总回溯不会超过O(n)
总O(nlogn)
4.找最近点对
给出平面内的n个点,找出距离最小的点
(1)
暴力搜索
n个点两两计算距离
N*(n-1)/2
(2)
分治
归纳
将原n个点找到x座标最中间的一个,以这个点的竖线分两堆
假设我们已知n/2个点堆中的最小距离
推广的n
左边最小值d1, 右边最小值d2
D= min(d1, d2)
计算竖线两边+-d范围内的点两两最小值
因为外面的不可能有跨界还小于d的
最坏情况
n个点都在中间区域内
。。。
Tn = 2T(n/2) + O(n^2)
还O(n^2)
优化
其实每个点找对面界中的点时
只用找[y - d, y + d]的点
有对面界的最小距离为d
将中间区域的点按y排序(O(nlogn))
每个点只会与对面界的最多6个点检查一遍
所以检查时间为常数O(n)
Tn = 2T(n/2) + O(nlogn)
O(n(logn)^2)
再优化
增强归纳
我们不但知道n/2堆的最小距离,我们还知道其中点y值的排序
这样求中间的时候就可以直接合并
类似于归并排序
Tn = 2T(n/2) + O(n)
O(nlogn)
5.求水平线与竖直线的交点
平面内有n条水平线,m条竖直线,求交点
(1)
暴力
两两求O(mn)
(2)
将所有线端点x值排序
O((m+n)log(m+n))
扫描线
设置一条竖线从平面左边到平面右边
(1)是左端点,就入队,表示这条线有产生交点的希望
(2)是右端点,就这条直线出队
(3)是竖线,就与队列中的水平线比较,是否产生交点
扫描
检查M+n个点
竖直线的话要检查所有水平点
最坏(m+n)n
优化
维护有希望的水平线以y值排序的堆
这样判断是否相交就用竖直线的两个端点二分查找
O(m+n)logn
总结
几何算法的问题我们常常会说这肉眼看看不就出来了吗,但几何算法就是这样,它是让计算机解的方法。设计几何算法时,要注意不要被脑子里的惯式图形所误导,要考虑特殊情况。