算法設計與分析05-最近點對算法

1.題目描述:

設S是平面上n個點的集合,在這一節中,我們考慮在S中找到一個點對p和q的問題,使其相互距離最短。換句話說,希望在S中找到具有這樣性質的兩點p1 = (x1,y1)和p2 = (x2,y2),使它們間的距離在所有S中點對間爲最小

2.解題思路

一共分爲三種情況

情況1:點數小於等於二時:直接計算,求該兩點之間的距離。

情況2:集合中有三個點:兩兩比較,求三個點中的最近的兩個點距離。

情況3:點數大於三時:首先劃分集合S爲SL和SR,使得SL中的每一個點位於SR中每一個點的左邊,並且SL和SR中點數相同。分別在SL和SR中解決最近點對問題,得到DL和DR,分別表示SL和SR中的最近點對的距離。令d=min(DL,DR)。如果S中的最近點對(P1,P2)。P1、P2兩點一個在SL和一個在SR中,那麼P1和P2一定在以L爲中心的間隙內,以L-d和L+d爲界。如圖1.21

圖 1.21

 

對於情況3, 如果在SL中的點P和在SR中的點Q成爲最近點對,那麼P和Q的距離必定小於d。因此對間隙中的每一個點,在合併步驟中,只需要檢驗yp+d和yp-d內的點即可。

步驟1:根據點的y值和x值對S中的點排序。

步驟2:找出中線L將S劃分爲SL和SR

步驟3:將步驟2遞歸的應用解決SL和SR的最近點對問題,並令d=min(dL,dR)。

步驟4:將L-d~L+d內的點以y值排序,對於每一個點(x1,y1)找出y值在y1-d~y1+d內的接下來的7個點,計算距離爲d’。如果d’小於d,令d=d’,最後的d值就是答案。

對於合併結果的解釋:對於劃分後的圖如圖2.2.2

圖 2.2.2

解釋:

  1. 設d  = min{dll, drr},如果最近點對由Sl中的某個點pl與Sr中的某個點pr組成,則pl和pr一定在劃分線L的距離d內。這樣,如果令S’l和S’r分別表示爲在線L距離內的Sl和Sr 中的點,則pl一定在S’l中, pr一定在S’r中。
  2. 假設d’≤ d  ,則存在兩點pl∈S’l和pr∈S’r ,有d(pl, pr) = d’,從而pl和pr之間的垂直距離不超過d

  1. 因爲pl,pr這兩點都在以垂直線L爲中心的d×2d矩形區內或其邊界上
  2. 設T是兩個垂直帶內的點的集合

 

  1. 如果在d×2d矩形區內,任意兩點間的距離一定不超過d,則這個矩形最多能容納8個點,其中至多4個點屬於Sl, 4個點屬於Sr。

 

  1. T中的每個點最多需要和T中按照y軸排序後鄰接的7個點進行比較。

 

3.代碼如下:

  1 // Closest-Pair.cpp: 定義控制檯應用程序的入口點。

  2 //

  3

  4 #include "stdafx.h"

  5 #include<ctime>

  6 #include<iostream>

  7 #include<cmath>

  8 #include<algorithm>

  9

 10 using namespace std;

 11 //定義橫縱座標對大範圍

 12 #define RANGE 100.0

 13 //定義無限大數字

 14 #define INFINATE_DISTANCE 65535

 15 //point 點對結構體

 16 typedef struct Point {

 17   double x;

 18   double y;

 19 }Point;

 20 //隨機生成一定數量座標

 21 void SetPoints(Point *points, int length) {

 22   srand(unsigned(time(NULL)));

 23   for (int i = 0; i < length; i++) {

 24     points[i].x = (rand() % (int)(RANGE * 200)) / RANGE - RANGE;

 25     points[i].y = (rand() % (int)(RANGE * 200)) / RANGE - RANGE;

 26   }

 27 }

 28 //求出兩點之間距離->Distance

 29 double Distance(Point point1, Point point2) {

 30   return sqrt((point1.x - point2.x)*(point1.x - point2.x) + (point1.y - point2.y)*(point1.y - point2.y));

 31

 32 }

 33 //自定義排序,按照x座標排序

 34 bool CompX(Point a, Point b) {

 35   return a.x < b.x;

 36 }

 37 //自定義排序,按照Y座標排序

 38 bool CompY(Point a, Point b) {

 39   return a.y < b.y;

 40 }

 41 //利用分治思想進行查找最近點對->ClosestPair()

 42 double ClosestPair(Point points[], int length, Point &a, Point &b) {

 43   double distance;

 44   double d1, d2;//左右兩邊子集各自的最近距離

 45   Point a1, b1, a2, b2;//分割後生成的左右兩邊子集的最近點對

 46   int i, j, k,m=0;

 47 //先判斷length的個數

 48   if (length <2) {

 49     distance = INFINATE_DISTANCE;

 50   }

 51   else if (length == 2) {

 52     a = points[0];

 53     b = points[1];

 54     distance = Distance(a, b);

 55   }

 56   else {

 57

 58

 59     //如果長度大於3,則生成兩個子集

 60

 61       //先將points按照x座標進行升序排序

 62     sort(points, points + length, CompX);

 63       //將升序後的左半邊子集賦值給ptsl,右半邊賦值給ptsr

 64     Point *ptsl=new Point[length];

 65     Point *ptsr = new Point[length];

 66     for (i = 0; i < (length) / 2; i++) {

 67       ptsl[i] = points[i];

 68     }

 69     for (j = 0, k = length / 2; k < length; k++) {

 70       ptsr[j++] = points[k];

 71     }

 72       //對左半邊子集進行遞歸操作,返回d1

 73     d1 = ClosestPair(ptsl, length / 2, a1, b1);

 74     d2 = ClosestPair(ptsr, length - (length / 2), a2, b2);

 75       //對右半邊子集進行遞歸操作,返回d2

 76

 77       //比較d1,d2,求出兩者之間最小的距離

 78     //distance = d1 < d2 ? d1 : d2;

 79     if (d1 < d2) {

 80       distance = d1; a = a1; b = b1;

 81     }

 82     else {

 83       distance = d2; a = a2; b = b2;

 84     }

 85       //取得距離中線2δ距離的共K個點

 86     double mid = points[(length - 1) / 2].x;//中線

 87     Point *pts = new Point[length];

 88     for (i = 0, k = 0; i < length; i++) {

 89       if (abs(points[i].x - mid) <= distance) {

 90         pts[k++] = points[i];

 91       }

 92     }

 93       //將這K個點按照y座標排序

 94     sort(pts, pts + k, CompY);

 95       //將左邊的點與右半邊的排好序的6個點進行距離比較

 96     for (i = 0; i < k; i++) {

 97       //只判斷左側部分的點

 98       if (pts[i].x - mid > 0)

 99         continue;

100       m = 0;

101       //只對按照Y排序後的鄰接6個點進行比較

102       for (j = i + 1; j < i + 6 + m&&j<k; j++) {

103         if (pts[j].x - mid < 0) {

104           //只判斷中線右邊的點

105           m++;

106           continue;

107         }

108         if (Distance(pts[i], pts[j]) < distance) {

109           distance = Distance(pts[i], pts[j]);

110           a = pts[i];

111           b = pts[j];

112         }

113       }

114

115     }

116   }

117   return distance;

118 }

119

120

121 int main()

122 {

123   int num;

124   Point a, b;

125   Point *points;

126   double distance;

127   cout << "請輸入點對的個數:";

128   cin >> num;

129   if (num < 2) {

130     cout << "請輸入數目超過2的個數" << endl;

131   }

132   else {

133

134     points = new Point[num];

135     SetPoints(points, num);

136     cout << "隨機生成的二維點對如下:" << endl;

137     for (int i = 0; i < num; i++) {

138       cout  << "(" << points[i].x << "," << points[i].y << ")" << endl;

139

140     }

141     distance = ClosestPair(points, num, a, b);

142     cout << endl <<endl << "按照橫座標排序後的點對爲:" << endl;

143     for (int i = 0; i < num; i++) {

144       cout << "(" << points[i].x << "," << points[i].y << ")" << endl;

145     }

146     cout << "最近距離的點對爲:" << endl;

147     cout << "(" << a.x << "," << a.y << ")" <<"  "<< "(" << b.x << "," << b.y << ")" << endl;

148  cout << "最近點對之間的距離爲:" << endl;
149     cout << distance << endl;
150   }
151     return 0;
152 }

4.結果截圖

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章