【本文链接】

http://www.cnblogs.com/hellogiser/p/closest-pair-problem.html

【题目】

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

【蛮力法】

对于n个点,一共可以组成n(n-1)/2对点对,对这n(n-1)/2对点对逐对进行距离计算,通过循环求得点集中的最近点对。时间复杂度为T(n)=n^2。

C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/7/11
*/
struct Point
{
    double x;
    double y;
}

double distance(const Point &a, const Point &b) const
{
    // distance of point a and b
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}

double ClosestPairBruteforce(Point P[], int n)
{
    // O(n^2)
    // input: a list P of n points
    // output: distance of the closest pair of points
    double dmin = DBL_MAX;
    int i, j;
    ; i < n; i++)
        ; j < n; j++)
        {
            d = distance(P[i], P[j]);
            if (d < dmin)
            {
                dmin = d;
            }
        }
    return dmin;
}

【分治法】

首先划分集合S为SL和SR,使得SL中的每一个点位于SR中每一个点的左边,并且SL和SR中点数相同。分别在SL和SR中解决最近点对问题,得到d1和d2,分别表示SL和SR中的最近点对的距离。令d=min(d1,d2)。如果S中的最近点对(p,q),p在SL并且q在SR中,那么p和q一定在以L为中心的带状区域内,以L-d和L+d为界,如下图所示:

可以证明,对于[L-d,L]区域中的p点,在[L,L+d]中至多需要计算与6个点之间的距离。(证明略)

思路如下

Pseudo Code  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/7/11
*/
ClosestPair(S)
     return DBL_MAX
    ])
    //otherwise,do the following
    let L = median(S)
    divide S into SL and SR at L
    d1 = CloestPair(SL)
    d2 = CloestPair(SR)
    d12 = CrossPair(SL,SR)
    return min(d1,d2,d12)

时间复杂度为T(n)=2T(n/2)+(n/2)*6,可以得到时间复杂度为O(nlgn)。

具体步骤如下:

Step 0  Sort the points by x (list one) and then by y (list two).
 
Step 1 Divide the points given into two subsets S1 and S2 by a vertical line x = m so that half the points lie to the left and half the points lie to the right.
(Note: set m = (x[N/2]+x[N/2+1])/2 so that no points lie on the split line.)
 
Step 2  Find recursively the closest pairs for the left and right subsets.
 
Step 3   Set d = min{d1, d2}
        We can limit our attention to the points in the symmetric vertical strip of width 2d as possible closest pair. Let C1 and C2 be the subsets of points in the left subset S1 and of the right subset S2, respectively, that lie in this vertical strip. The points in C1 and C2 are stored in increasing order of their y coordinates, taken from the second list.
 
Step 4   For every point P(x,y) in C1, we inspect points in C2 that may be closer to P than d.  There can be no more than 6 such points (because dd2)!
 伪代码如下:

Pseudo Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 
/*
    version: 1.0
    author: hellogiser
    blog: http://www.cnblogs.com/hellogiser
    date: 2014/7/11
*/
GetCloestPair(pts, n)
    copy pts[]
    qsort(ptsByX,cmpX)
    qsort(ptsByY,cmpY)
    ClosestPair(ptsByX, ptsByY, n)

ClosestPair(ptsByX, ptsByY, n)
      // Base cases
) return INT_MAX
    ])
    // Divide S into SL SR by line x = xm
 
    copy ptsByX[ . . . mid] into new array XL in x order
    copy ptsByX[mid+ . . . n−1] into new array XR
    copy ptsByY[ . . . mid] into new array YL in y order
    copy ptsByY[mid+ . . . n−1] into new array YR
     // XL and YL refer to same points, as do XR,YR.
    // Conquer
))
    d2 = ClosestPair(XR, YR, ceil(n/))
    // Combine sub solutions to final solution
    d12 = CrossPair(ptsByX,XL,XR,n,d1,d2);
    return min(d1,d2,d12)

其中最为重要的是CrossPair步骤。

 Pseudo Code  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 
CrossPair(ptsByX,XL,XR,n,d1,d2)
    mid = n/
    d =  min(d1, d2)
    xm = (ptsByX[mid]+ptsByX[mid+
    //C1: Select points in XL where x>xm-d
    i = mid
    &&XL[i].x>xm-d)
            add XL[i] to C1
            i = i-
    //C1=XL[i+1..mid]
    //C2: Select points in XR where x<xm+d

&&XR[j].x<xm+d)
            add XR[j] to C2
            j = j+
    //C2=XL[mid+1..j-1]
    // For given Point P in C1, there are at most 6 points in C2 within distance of d
    minDist = DBL_MAX
    ;i<C1.length;i++)
        p = C1[i]
        ;j<C2.length;j++)
            q = C2[j]
            // Make sure Q within d*2d rectangel of P(at most 6 Q)
                if(p.y-d<q.y<p.y+d)
                            dist = distance(p,q)
                            if(minDist>dist) 
                                    minDist = dist
    return minDist

可以通过left和right下标来表示C1和C2,这样可以进一步优化为

Pseudo Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 
CrossPair(ptsByX,XL,XR,n,d1,d2)
    mid = n/
    d = min(d1, d2)
    xm = (ptsByX[mid]+ptsByX[mid+
    //C1: Select points in XL where x>xm-d
    i = mid
    &&XL[i].x>xm-d)
            i = i-
    left = i+
    //C1=XL[left..mid]
    //C2: Select points in XR where x<xm+d

&&XR[j].x<xm+d)
            j = j+
    right = j-
    //C2=XL[mid+1..right]
    // For given Point P in C1, there are at most 6 points in C2 within distance of d
    minDist = DBL_MAX
    for(i=left;i<=mid;i++)
        p = XL[i]
        ;j<=right;j++)
            q = XR[j]
            // Make sure Q within d*2d rectangel of P(at most 6 Q)
                if(p.y-d<q.y<p.y+d)
                            dist = distance(p,q)
                            if(minDist>dist) 
                                    minDist = dist
    return minDist

【参考】

2.11 2D平面最近点对问题[closest pair problem]的更多相关文章

  1. uva10245-The Closest Pair Problem(平面上的点分治)

    解析:平面上的点分治,先递归得到左右子区间的最小值d,再处理改区间,肯定不会考虑哪些距离已经大于d的点对,对y坐标归并排序,然后从小到大开始枚举更新d,对于某个点,x轴方向只用考虑[x-d,x+d]( ...

  2. UVA 10245 The Closest Pair Problem 最近点问题 分治算法

    题意,给出n个点的坐标,找出两点间最近的距离,如果小于10000就输出INFINITY. 纯暴力是会超时的,所以得另辟蹊径,用分治算法. 递归思路将点按坐标排序后,分成两块处理,最近的距离不是在两块中 ...

  3. 求最近点对算法分析 closest pair algorithm

    这个帖子讲得非常详细严谨,转一波. http://blog.csdn.net/lishuhuakai/article/details/9133961

  4. wannafly 练习赛11 E 求最值(平面最近点对)

    链接:https://www.nowcoder.com/acm/contest/59/E 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536K 64bit ...

  5. 平面最近点对(分治nlogn)

    平面最近点对,是指给出平面上的n个点,寻找点对间的最小距离 首先可以对按照x为第一关键字排序,然后每次按照x进行分治,左边求出一个最短距离d1,右边也求出一个最短距离d2,那么取d=min(d1, d ...

  6. P1429 平面最近点对(加强版)(分治)

    P1429 平面最近点对(加强版) 主要思路: 分治,将点按横坐标为第1关键字升序排列,纵坐标为第2关键字升序排列,进入左半边和右半边进行分治. 设d为左右半边的最小点对值.然后以mid这个点为中心, ...

  7. 计算几何 平面最近点对 nlogn分治算法 求平面中距离最近的两点

    平面最近点对,即平面中距离最近的两点 分治算法: int SOLVE(int left,int right)//求解点集中区间[left,right]中的最近点对 { double ans; //an ...

  8. HDU-4631 Sad Love Story 平面最近点对

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4631 数据是随机的,没有极端数据,所以可以分段考虑,最小值是一个单调不增的函数,然后每次分治算平面最近 ...

  9. HDU1007--Quoit Design(平面最近点对)

    Problem Description Have you ever played quoit in a playground? Quoit is a game in which flat rings ...

随机推荐

  1. iOS边练边学--static(作用域),copy(深浅拷贝)

    一.static作用 二.copy

  2. hdu2846 字典树

    给你一堆字符串,然后再给你几个查询,前面那些字符串中有多少个包含了这个串.所以可以把开始inset()的字符遍历一遍,同时可能出现该字符串在某个字符串中有多次出现,所以还要用flag标记,来区分不同的 ...

  3. Java设计模式-单例模式(Singleton)

    单例对象(Singleton)是一种常用的设计模式.在Java应用中,单例对象能保证在一个JVM中,该对象只有一个实例存在.这样的模式有几个好处: 1.某些类创建比较频繁,对于一些大型的对象,这是一笔 ...

  4. Python 之我见

    读音 Python(KK 英语发音:/ˈpaɪθən/) 序言 其实早前就已经接触了python这个功能强大的脚本语言,但是那时只是基于兴趣而学习,目的性并不是很强,所以学习的并不是很深入.最近由于闲 ...

  5. MyEclipse10中导入的jquery文件报错(出现红叉叉,提示语法错误)

    为了做一个页面特效,导入了一个jQuery文件,怎想,myeclipse竟然报错说是语法错误,但是这个js文件我是从官网上下载的,不应该出错才对,百度谷歌之后终于找到了解决办法: 选中报错的js文件, ...

  6. 从HashMap透析哈希表

    ##扯数据结构 先看一下哈希表的概念: 哈希表是一种数据结构,它可以提供快速的插入操作和查找操作.第一次接触哈希表,他会让人难以置信,因为它的插入和删除.查找都接近O(1)的时间级别.用哈希表,很多操 ...

  7. shell中条件判断if中的-z到-d的意思

    shell中条件判断if中的-z到-d的意思 [ -a FILE ] 如果 FILE 存在则为真. [ -b FILE ] 如果 FILE 存在且是一个块特殊文件则为真. [ -c FILE ] 如果 ...

  8. Color Space

    色域(Color Space),又被称为色彩空间,它代表了一个色彩影像所能表现的色彩具体情况.我们经常用到的色彩空间主要有RGB.CMYK.Lab等,而RGB色彩 空间又有AdobeRGB.Apple ...

  9. Linux下如何搭建VPN服务器(转)

    VPN服务器的配置与应用 实验场景 通过将Linux配置VPN服务器允许远程计算机能够访问内网. 我的目的: 现在需要开发第三方接口,而第三方接口有服务器IP地址鉴权配置,这样在本地开发出来的程序每次 ...

  10. Linux中iptables设置详细(转)

    无论如何,iptables是一个需要特别谨慎设置的东西,万一服务器不在你身边,而你贸然设置导致无法SSH,那就等着被老板骂吧,呵呵... 以下内容是为了防止这种情况发生而写的,当然很初级,不过一般服务 ...