天天看点

寻找最远点对

在一个实际项目中遇到“寻找最远点对”问题,猛然想起《编程之美》扩展问题提到过,开心地翻出来看,却发现“最近点对”的思路套“最远”貌似不合适。

然后开始查文献、做实验,改进算法,困扰半天也发现了不少实际问题,写出来大家参考。最后,算法用到系统中,虽然没有大幅提高遗传算法效率,但是系统评价功能明显比原来快了n倍,可谓酣畅:)

找回昔日研究《编程之美》感觉~~

问题

给定平面上N个点的坐标,找出距离最远的两个点。

背景

如果我们希望在城市道路网上设传感器,用以追踪车辆。那么这些传感器布应该设在哪里,布设多少?

首先来看看问题规模,例如:某城市二环内共有4210个路段,每个路段上有“设置/不设置”两种可能,那么所有可能的方案数为:

寻找最远点对

假设希望路网中不存在“行驶很远而不被追踪到的路径”,那么可以认为“用尽量少的传感器分割路网达到安全标准”的方案是优秀的。

对于这么大规模的问题,可以采用遗传算法(GA)进行优化求解。而在GA中,需要对每一个方案进行评估(按照一定的标准)。

那么,评估过程中,为了找出“行驶很远而不被追踪到的路径”,需要找到“最远点对”。

分析

类似于“最近点对问题”,这个问题也可以用枚举的方法求解,时间复杂度O(n^2)。

“寻找最近点对”是用到分治策略降低复杂度,而“寻找最远点对”可利用几何性质。注意到:对于平面上有n个点,这一对最远点必然存在于这n个点所构成的一个凸包上(证明略),那么可以排除大量点,如下图所示:

寻找最远点对

在得到凸包以后,可以只在顶点上面找最远点了。同样,如果不O(n^2)两两枚举,可以想象有两条平行线, “卡”住这个凸包,然后卡紧的情况下旋转一圈,肯定就能找到凸包直径,也就找到了最远的点对。或许这就是为啥叫“旋转卡壳法”。(当然这个方法还能解决凸包很多别的问题 http://cgm.cs.mcgill.ca/~orm/rotcal.html )

寻找最远点对

总结起来,问题解决步骤为:

1. 用Graham's Scanning求凸包

2. 用Rotating Calipers求凸包直径,也就找到了最远点对。

该算法的平均复杂度为O(nlogn) 。最坏的情况下,如果这n个点本身就构成了一个凸包,时间复杂度为O(n^2)。

继续阅读