[翻译]扫描线算法(Line Sweep Algorithm)(1)
来源:互联网 发布:商城系统数据库设计 编辑:程序博客网 时间:2024/06/03 20:07
原地址:https://www.hackerearth.com/zh/practice/math/geometry/line-sweep-technique/tutorial/
在cf评论区偶然看见的,顺便学习一下好了……然后发现是个大坑
我英语比较菜,如有谬误还请纠正……
在这篇文章,我们将会学到一些基于计算几何的算法。
扫描线是一条想象中的向右扫过平面的竖直线。也因此,以此思想为基础的算法也被称为平面扫描算法(Plane Sweep Algorithm),我们以某些事件为基础扫描我们思考的问题以使扫描离散化。
这些事件都是以我们思考的问题为基础,我们将在下面讨论的算法中看见。除去这些事件以外,我们需要维护一些数据结构来储存以y坐标为顺序排列的点(这一顺序有时可能会改变)以助益于在扫描到某些事件时进行操作。在一些情况,该数据结构只储存活动事件。
另一个需要注意的事情是,这种算法的效率取决于我们选用的数据结构。一般地,我们可以用C++中的set,但有时可能我们需要储存更多东西,所以我们可能采用平衡二叉树。
让我们思考我们的第一个算法。
最近的点(Closest Pair)
问题:从互不相同的N个点中找出最近的两个。
这个问题可以通过暴力枚举每两个点解决,不过这样复杂度为
对这个问题我们可以考虑在数组中作为事件的的点。在一个set中,我们将已经访问过的点按y坐标排列,因此在从左向右扫描时首先我们以x坐标排序。
现在想象我们已经扫描过1至N-1,令h为我们得到的最短距离。对第N个点,我们想要找到距离小于等于h的点,而对于横坐标,只有横坐标范围在
一个需要注意的事情是,对许多情况,是活动事件的点的数量是O(1)的(除该点本身外最多可以有5个点是活动的)(不是很懂这句,原句:One thing to note is that at any instance, the number of points which are active events is O(1)(there can be atmost 5 points around a point which are active excluding the point itself))
好的,理论已经够多了,让我们看看这个算法的运作。
将h初始化为开始的两个点,若现在的距离小于h则更新h的值。
图片中红色区域包括的点是被当前点评估的点。这些点左侧是已经被移除set的点。
下面是上述算法的cpp代码:
#define px second#define py firsttypedef pair<long long, long long> pairll;pairll pnts [MAX];int compare(pairll a, pairll b){ return a.px<b.px; }double closest_pair(pairll pnts[],int n){ sort(pnts,pnts+n,compare); double best=INF; set<pairll> box; box.insert(pnts[0]); int left = 0; for (int i=1;i<n;++i) { while (left<i && pnts[i].px-pnts[left].px > best) box.erase(pnts[left++]); for(typeof(box.begin()) it=box.lower_bound(make_pair(pnts[i].py-best, pnts[i].px-best));it!=box.end() && pnts[i].py+best>=it->py;it++) best = min(best, sqrt(pow(pnts[i].py - it->py, 2.0)+pow(pnts[i].px - it->px, 2.0))); box.insert(pnts[i]); } return best;}
让我们来分解一下上述代码:
1.首先,我们以x为参数排序了点的数组
2.之后我们将数组pnts的第一个点加入了set中。注意,我们已经将纵坐标作为pair的第一个参数,所以set将以y坐标为参数排列。
3.在第一重循环的第一个子循环中,对每个pnts中的点,我们清除掉
4.在第二个子循环中,我们遍历了所有所有横坐标在
5.将每个点插入至set中,O(logn)
综上所述,时间复杂度为O(NlogN)。接下来让我们看下一个问题。
- [翻译]扫描线算法(Line Sweep Algorithm)(1)
- [翻译]扫描线算法(Line Sweep Algorithm)(2)
- 轮廓线扫描算法:Theo Pavlidis' Algorithm
- Sweep and Prune Algorithm - Introduction
- 标记-清除( Mark-Sweep )算法
- 扫除算法(sweep)求逆矩阵
- 扫除算法(sweep)求逆矩阵
- PhysX官方手册翻译 - 扫掠API(Sweep API)
- Graham扫描算法(Graham Scan Algorithm)
- sweep算法计算intersect
- Mark-Sweep算法
- 算法库algorithm-1-algorithm
- 扫描线填充算法(1)
- uva 972 - Horizon Line(平移扫描线)
- Lesson 1: Bresenham’s Line Drawing Algorithm
- Garbage Collection | Mark-Sweep算法
- Sweep
- 算法实现(1):Ford-Fulkerson Algorithm
- 288
- 289
- 第三章 高级装配
- robot framework selenium 指定浏览器版本启动
- Android 更换壁纸 代码
- [翻译]扫描线算法(Line Sweep Algorithm)(1)
- [Python] wxPython 编辑框组件学习总结 (原创)
- 矩阵压缩
- HDU 2853 Assignment(二分图最优匹配:优先用原匹配边)
- [Linux]--标准文件 IO 基本操作
- nrf51822/nrf52832开发过程中一些常用的API函数
- 如何正确使用Bundle
- android webview组件的使用
- 闭包--整理