平面最近点对
引入
给定
下面我们介绍一种时间复杂度为
过程
与常规的分治算法一样,我们将这个有
我们先将所有点按照
并递归下去,求出两点集各自内部的最近点对,设距离为
现在该合并了!我们试图找到这样的一组点对,其中一个属于
结合图像,直线
再根据
对于
在点集
如果我们将
由此我们得到了合并的步骤:
- 构建集合
。 - 将
中的点按照 排序。通常做法是 ,但是我们可以改变策略优化到 (下文讲解)。 - 对于每个
考虑 ,对于每对 计算距离并更新答案(当前所处集合的最近点对)。
注意到我们上文提到了两次排序,因为点坐标全程不变,第一次排序可以只在分治开始前进行一次。我们令每次递归返回当前点集按
似乎这个算法仍然不优,
复杂度证明
我们已经了解到,
我们再将这个矩形拆分为两个
我们将一个
由此,每个正方形中最多有
实现
我们使用一个结构体来存储点,并定义用于排序的函数对象:
为了方便实现递归,我们引入 upd_ans()
辅助函数来计算两点间距离并尝试更新答案:
下面是递归本身:假设在调用前 a[]
已按
我们使用 std::inplace_merge()
来执行归并排序,并创建辅助缓冲区 t[]
,
在主函数中,这样开始递归即可:
推广:平面最小周长三角形
上述算法有趣地推广到这个问题:在给定的一组点中,选择三个点,使得它们两两的距离之和最小。
算法大体保持不变,每次尝试找到一个比当前答案周长
非分治算法
过程
其实,除了上面提到的分治算法,还有另一种时间复杂度同样是
我们可以考虑一种常见的统计序列的思想:对于每一个元素,将它和它的左边所有元素的贡献加入到答案中。平面最近点对问题同样可以使用这种思想。
具体地,我们把所有点按照
- 将所有满足
的点从集合中删除。它们不会再对答案有贡献。 - 对于集合内满足
的所有点,统计它们和 的距离。 - 将
插入到集合中。
由于每个点最多会被插入和删除一次,所以插入和删除点的时间复杂度为
实现
期望线性做法
其实,除了上面提到的时间复杂度为
首先将点对 随机打乱,我们将维护前缀点集的答案。考虑从前
记前
如果这一过程中,答案被更新,我们就重构网格图,否则不重构。在前
习题
- UVA 10245 "The Closest Pair Problem"[难度:低]
- SPOJ #8725 CLOPPAIR "Closest Point Pair"[难度:低]
- CODEFORCES Team Olympiad Saratov - 2011 "Minimum amount"[难度:中]
- SPOJ #7029 CLOSEST "Closest Triple"[难度:中]
- Google Code Jam 2009 Final "Min Perimeter"[难度:中]
参考资料与拓展阅读
本页面中的分治算法部分主要译自博文 Нахождение пары ближайших точек 与其英文翻译版 Finding the nearest pair of points。其中俄文版版权协议为 Public Domain + Leave a Link;英文版版权协议为 CC-BY-SA 4.0。
贡献者:@Jimmy@Menci@Ancker-0@Anakin@Ir1d@mgt@Xeonacid@Shuhao@邵晨恒@sshwy@countercurrent_time
本页面最近更新:2/3/2023, 12:00:00 AM,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用