【本文链接】

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. hdu1853 km算法

    //hdu1853 #include<stdio.h> #include<string.h> #define INF 99999999 ][],pr[],pl[],visr[] ...

  2. UVA5870 乱搞 Smooth Visualization

    #include<stdio.h> #include<string.h> #define maxn 1201 ][],s[maxn]; int col; int getmax( ...

  3. struts2理解

    (1) Struts2(一)---struts2的环境搭建及实例 (2) struts2(二)---ModelDriven模型驱动 (3) Struts2属性驱动与模型驱动 (4)

  4. 【BZOJ-1452】Count 树状数组 套 树状数组

    1452: [JSOI2009]Count Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1769  Solved: 1059[Submit][Stat ...

  5. Put-Me-Down项目Postmortem

    设想和目标 PMD是一款帮助低头族控制使用手机时间的APP,设想按照需求规格说明书内容实现功能,能将数据备份到服务器. 计划 初始计划我们是想将程序方面分为安卓和后台,主要是程序方面的工作.我们对项目 ...

  6. hadoop单节点windows 7 环境搭建

    前言 Windows下运行,通常有两种方式:一种是用VM方式安装一个,这样基本可以实现全Linux环境的Hadoop运行:另一种是通过Cygwin模拟Linux环境.后者的好处是使用比较方便,安装过程 ...

  7. Asp.Net MVC3 简单入门详解过滤器Filter

    http://www.cnblogs.com/boruipower/archive/2012/11/18/2775924.html 前言 在开发大项目的时候总会有相关的AOP面向切面编程的组件,而MV ...

  8. MyEclipse------制作通讯录

    addinfo.java public class addinfo extends HttpServlet { private String url="jdbc:mysql://localh ...

  9. MyEclipse------executeBatch()使用方法

    executeBatch()方法用于成批地执行SQL语句,但不能执行返回值是ResultSet结果集的SQL语句,而是直接执行stmt.executeBatch(); 辅助方法: addBatch() ...

  10. hud 2502 月之数

    I think: AC : import java.util.Scanner; public class Main { public static void main(String[] args) { ...