【本文链接】

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. java Thread编程(三) 同步的两种不同实现方式

    1,创建需要同步的对象(方式一) package concurrency; public class Bank { private double amount; public Bank(double ...

  2. form表单提交和ajax提交的区别

    form表单是整个页面跳到服务器的地址然后提交数据: ajax是往这个地址post数据 <form style="padding:0px;margin:0px;" targe ...

  3. IIS7部署项目时提示:"错误消息 401.2。: 未经授权: 服务器配置导致登录失败。"的解决办法

    这个错误的定位:你的站点使用了Forms验证,而且在部署在生产环境的时候,设置错误,或者注释了. 解决方法如下: 1.检查Forms配置是否屏蔽. 2.有权限访问的资源是否已经开发. 基本就围绕以上两 ...

  4. FireFox插件

    Firebug和YSlow就不说了,太常用了,开发必备.

  5. crossdomain.xml的配置详解

    目录 1 简介 2 crossdomain.xml的配置详解 3 总结 1 简介 flash在跨域时唯一的限制策略就是crossdomain.xml文件,该文件限制了flash是否可以跨域读写数据以及 ...

  6. 初学structs2,表单验证简单补充

    一.使用注解方式,跳过验证某个方法 由于在开发中,我们不需在请求每一个action类中的方法时都要走validate方法,那么我们可以在这些不需要验证的方法上加上@SkipValidation注解即可 ...

  7. --hdu 2124 Repair the Wall(贪心)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2124 Ac code : #include<stdio.h> #include<st ...

  8. 使用存取方法来设置Property value

    对比如下代码,第一种使用了存取方法来设置,第二种直接对实例变量操作.显然我们应该采用第一种, 使用第二种情况,简单的情况还好,如果情况一旦复杂,就非常容易出错.并且直接对实例变量操作,不会引发KVO通 ...

  9. rsyslog 与 logrotate 服务

    rsyslog与logrotate服务 rsyslog 负责写入日志, logrotate负责备份和删除旧日志, 以及更新日志文件. 一.rsyslog rsyslog 是一个 syslogd 的多线 ...

  10. centos安装gitlab

    原文链接: http://www.centoscn.com/image-text/install/2015/0320/4929.html http://www.01happy.com/centos-6 ...