算法设计与分析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.结果截图

 

    原文作者:算法
    原文地址: https://www.twblogs.net/a/5bd3a82e2b717778ac20a789
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞