1. 问题
给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。严格地说,最接近点对可能多于1对。为了简单起见,这里只限于找其中的一对。
2. 解析
蛮力法:在蛮力法实现最近点对问题中,将问题简化:距离最近的点对可能多于一对,找出一对即可,另外只考虑二维平面中的情况。此处考虑到
直接用公式计算其距离(欧几里得距离):
通过遍历所有点集,计算出每一个点对的距离,计算出最近的距离并输出。避免同一对点计算两次,只考虑i<j的点对(pi,pj)。
其主要循环的步骤就是求出平方值,执行的次数为:
分治法:令P为笛卡儿平面上n>1个点构成的集合。简单起见,假设集合中的每个点都不一样。我们还假设这些点是按照其x轴坐标升序排列的。(如果不是这样,可以事先用类似合并排序这样的高效算法对其排序。)为了更加方便,我们还可以按照点的y轴坐标在另一个列表中进行升序排列,并将这个列表示为Q。
当2≤n≤3时,问题就可以通过蛮力算法求解。当n>3时,可以利用点集在x轴方向上的中位数m,在该处作一条垂线,将点集分成大小分别为(n/2上取整)和(n/2下取整)的两个子集P和P.。即使得其中(n/2上取整)个点位于线的左边或线上,(n/2下取整)个点位于线的右边或线上。然后就可以通过递归求解子问题Pl和Pr来得到最近点对问题的解。其中dl和dr分别表示在Pl和Pr中的最近对距离,并定义d=min{dl,dr} 。
但请注意,d不一定是所有点对的最小距离,因为距离最近的两个点可能分别位于分界线的两侧。因此,在合并较小子问题的解时,需要检查是否存在这样的点。显然,我们可以只关注以分割带为对称的、宽度为2d的垂直带中的点,因为任何其他点对的距离都至少为d(图5.7(a))。
设S是来自Q,位于分割线2d宽度范围内的垂直带的点的列表。由于Q的特点,因此S是按照y轴坐标升序排列的。我们扫描该列表,当遇到更近的点对时,更新目前为止的最小距离dmin。初始情况下dmin=d, 但接下来dmin≤d。设p(x,y) 为列表中的点。如果另一个点p(x,y) 和p点的距离小于dmin, 那么在列表S中,p’点一定位于p点后面, 并且两点在y轴上的距离一定要小于dmin(为什么?) 。在几何上, 这也就意味着p’点一定包含在图5.7(b)的矩形内。该算法的主要原理利用了以下事实:矩形内一般只能够包含少量候选点,因为在矩形每一边(左半边和右半边)内,点与点的距离至少为d。其实很容易证明,在矩形中满足条件的点(包括p在内)的总数不超过8个,更细致的研究表明这个数不会大于6。也就是说, 在移动到下一个点之前, 算法最多只需要考虑列表S中点p后面的5个点。
3. 设计
//使用蛮力算法来求解最近点对问题
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
dist=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);//计算距离
if(dist<minDist){
minDist=dist;//找出最小距离
x1=x[i];y1=y[i];//记录最小距离两点的坐标
x2=x[j];y2=y[j];
}
}
}
//使用分治算法来求解最近点对问题
//输入:数组P中存储了平面上的n≥2个点,并且按照这些点的x轴坐标升序排列
// 数组Q存储了与P相同的点,只是它是按照这点的y轴坐标升序排列
//输出:最近点对之间的欧几里得距离
If n≤ 3
返回由蛮力算法求出的最小距离
else
划分:m==S中各点x坐标的中位数;
d1 = 计算{(x1,y1),…,(xm,ym)}的最近对距离;
d2 = 计算{(xm,ym),…,(xn,yn)}的最近对距离;
d = min(d1,d2);
依次考察集合S中的点p(x,y),如果(x<=xm 并且x>=xm-d),则将点p放入集合P1中;如果(x>xm 并且x<=xm+d),则将点p放入集合P2中;
将集合P1和P2按y坐标升序排列;
对集合P1和P2中的每个点p(x,y),在y坐标区间[y,y+d]内最对取出6个候选点,计算与点p的最近距离d3;
返回min{d,d3};
4. 分析
蛮力算法时间复杂度:
T(n) =an² + bn + c
O(n)= n²
分治算法时间复杂度:
无论将问题划分成两个规模减半的子问题,还是合并子问题的解,该算法都只需要线性时间。因此,假设n是2的幂,我们得到算法运行时间的递归式:
T(n)=2T(n/2)+f(n)
其中f(n) 属于Q(n) 。应用主定理(其中,a=2,b=2,d=1) , 我们得到T(n) 属于Q(n logn) 。如果用O(n logn) 的算法来排序, 对输入点必须进行的预排序不会影响整体的效率类型。实际上,这是我们可能得到的最好效率,因为已经证明,在对算法可以执行的操作没有特殊假设的情况下, 该问题的任何算法都属于Ω(n logn)