最近点问题

本文介绍了如何在平面上找到最近的点对,分别阐述了蛮力算法和分治算法的实现细节。蛮力算法通过遍历所有点对计算距离,而分治算法利用中位数分割点集,通过递归和限制搜索范围提高效率,时间复杂度达到O(nlogn)。
摘要由CSDN通过智能技术生成

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)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
问题(closest pair problem)是指在一个平面给定n个点到其中距离最近的两个点的距离。这个问题可以用分治法来解决。具体的实现方法可以参考以下步骤: 1. 将所有按照x轴坐标排序 2. 分治,将集分为左右两部分,递归查左右两部分的最小距离 3. 在中间区域内(横跨左右两部分的区域),到距离中线最近的两个点的距离 4. 比较以上三个距离,取最小值作为最终结果 下面是一个简单的C++实现代码: ```c++ #include <iostream> #include <algorithm> #include <cmath> using namespace std; struct Point { int x, y; }; bool cmpX(Point a, Point b) { return a.x < b.x; } bool cmpY(Point a, Point b) { return a.y < b.y; } double getDistance(Point a, Point b) { return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y, 2)); } double merge(Point* points, int left, int mid, int right, double d) { Point* sortedPoints = new Point[right - left + 1]; int index = 0; int i = left, j = mid + 1; while (i <= mid && j <= right) { if (points[i].y < points[j].y) { sortedPoints[index++] = points[i++]; } else { sortedPoints[index++] = points[j++]; } } while (i <= mid) sortedPoints[index++] = points[i++]; while (j <= right) sortedPoints[index++] = points[j++]; for (int i = 0; i < index; i++) { for (int j = i + 1; j < index && sortedPoints[j].y - sortedPoints[i].y < d; j++) { double distance = getDistance(sortedPoints[i], sortedPoints[j]); if (distance < d) { d = distance; } } } return d; } double closestPair(Point* points, int left, int right) { if (left >= right) { return INT_MAX; } int mid = (left + right) / 2; double d1 = closestPair(points, left, mid); double d2 = closestPair(points, mid + 1, right); double d = min(d1, d2); return merge(points, left, mid, right, d); } int main() { int n; cin >> n; Point* points = new Point[n]; for (int i = 0; i < n; i++) { cin >> points[i].x >> points[i].y; } sort(points, points + n, cmpX); double ans = closestPair(points, 0, n - 1); cout << ans << endl; return 0; } ``` 其中,cmpX和cmpY是用于排序的比较函数,getDistance用于计算两之间的距离,merge用于计算跨越左右两部分的区域内的最小距离,closestPair用于递归查左右两部分的最小距离并返回最终结果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值