【本文链接】

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. hdu5012 bfs

    比较简单的题 搜索4个方向,维护位子的值. #include<stdio.h> #include<string.h> #include<queue> using n ...

  2. Java算法-希尔排序

    希尔排序的诞生是由于插入排序在处理大规模数组的时候会遇到需要移动太多元素的问题.希尔排序的思想是将一个大的数组“分而治之”,划分为若干个小的数组,以 gap 来划分,比如数组 [1, 2, 3, 4, ...

  3. Http状态码集合

    忘了之前在哪里收集的了,先表示感谢. 状态码 含义 100 客户端应当继续发送请求.这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝.客户端应当继续发送请求的剩余部分,或者如果请 ...

  4. bzoj 3172 后缀数组|AC自动机

    后缀数组或者AC自动机都可以,模板题. /************************************************************** Problem: 3172 Us ...

  5. BZOJ-1226 学校食堂Dining 状态压缩DP

    1226: [SDOI2009]学校食堂Dining Time Limit: 10 Sec Memory Limit: 259 MB Submit: 588 Solved: 360 [Submit][ ...

  6. Exceptionless 本地部署

    免费开源分布式系统日志收集框架 Exceptionless 前两天看到了这篇文章,亲身体会了下,确实不错,按照官方的文档试了试本地部署,折腾一番后终于成功,记下心得在此,不敢独享. 本地部署官方wik ...

  7. CSS3系列三(与背景边框相关样式 、变形处理、动画效果)

    与背景相关的新增属性 大家都知道在HTML页面中,元素都是由以下几部分组成 使用background-clip来修改背景的显示范围,如果设定为border-box,则背景范围包含边框区域,如果设定为p ...

  8. #pragma预处理实例

    1.#include <stdio.h>#if defined(ANDROID20)    #pragma message("Compile Android SDK 2.0... ...

  9. java变量作用域

      1.public:public表明该数据成员.成员函数是对所有用户开放的,所有用户都可以直接进行调用 2.private:private表示私有,私有的意思就是除了class自己之外,任何人都不可 ...

  10. structs2标签简单实用,及自定义转换器示例代码

    一.在structs.xml中配置 <structs> <package name="tagp" namespace="/test" exte ...