程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 2.11 2D平面最近點對問題[closest pair problem],closestpair

2.11 2D平面最近點對問題[closest pair problem],closestpair

編輯:C++入門知識

2.11 2D平面最近點對問題[closest pair problem],closestpair


【本文鏈接】

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;
    for (i = 0; i < n; i++)
        for( j = i + 1; 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)
    if S.size=1 return DBL_MAX
    if S.size2=2 return distance(S[0],S[1])
    //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[0..n-1] to ptsByX[0..n-1],ptsByY[0..n-1]
    qsort(ptsByX,cmpX)
    qsort(ptsByY,cmpY)
    ClosestPair(ptsByX, ptsByY, n)

ClosestPair(ptsByX, ptsByY, n)
      // Base cases
    if (n = 1) return INT_MAX
    if (n = 2) return distance(ptsByX[0], ptsByX[1])
    // Divide S into SL SR by line x = xm
    mid = n/2 -1 
    copy ptsByX[0 . . . mid] into new array XL in x order
    copy ptsByX[mid+1 . . . n−1] into new array XR
    copy ptsByY[0 . . . mid] into new array YL in y order
    copy ptsByY[mid+1 . . . n−1] into new array YR
     // XL and YL refer to same points, as do XR,YR.
    // Conquer
    d1 = ClosestPair(XL, YL, floor(n/2))
    d2 = ClosestPair(XR, YR, ceil(n/2))
    // 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/2 -1
    d =  min(d1, d2)
    xm = (ptsByX[mid]+ptsByX[mid+1])/2
    //C1: Select points in XL where x>xm-d
    i = mid
    while(i>=0&&XL[i].x>xm-d)
            add XL[i] to C1
            i = i-1
    //C1=XL[i+1..mid]
    //C2: Select points in XR where x<xm+d
    j = mid+1
    while(j<=n-1&&XR[j].x<xm+d)
            add XR[j] to C2
            j = j+1
    //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
    for(i=0;i<C1.length;i++)
        p = C1[i]
        for(j=0;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/2 -1
    d = min(d1, d2)
    xm = (ptsByX[mid]+ptsByX[mid+1])/2
    //C1: Select points in XL where x>xm-d
    i = mid
    while(i>=0&&XL[i].x>xm-d)
            i = i-1
    left = i+1
    //C1=XL[left..mid]
    //C2: Select points in XR where x<xm+d
    j = mid+1
    while(j<=n-1&&XR[j].x<xm+d)
            j = j+1
    right = j-1
    //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]
        for(j=mid+1;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
【參考】

http://blog.csdn.net/junerfsoft/article/details/2975495

http://blog.csdn.net/midgard/article/details/4199043

http://www.cnblogs.com/AdaByron/archive/2011/10/07/2200966.html

http://www.cnblogs.com/pangxiaodong/archive/2011/09/30/2196684.html

【本文鏈接】

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


ACM:給定點集S,S中周長最小的三角形(點集中點數N<=20000),一個復雜度可接受的算法(n^2以下)

用分治就可以過了。樓主可以參考一下最近點對問題的算法:
en.wikipedia.org/...roblem

算法如下:先將所有的點按x坐標排序,然後每次分成左右兩個部分,分別遞歸求解這兩個點集中的最小周長。最後考慮跨越這兩個點集的3個點的最小周長,用當前求得的最優解可以縮小枚舉的范圍。
 


  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved