算法分析与实践-作业5

最近对问题

1. 问题

n个点在公共空间中,求出所有点对的距离最小值。

2. 解析

①    对所有的点按照x坐标从小到大排序。根据下标进行分割,使得点集分为两个集合。

②    递归的寻找两个集合中的最近点对。取两个集合最近点对中的最小值min(dis_left,dis_right)。

③    最近距离不一定存在于两个集合中,可能一个点在集合A,一个点在集合B,而这两点间距离小于dis。这其中如何合并是关键。根据递归的方法可以计算出划分的两个子集中所有点对的最小距离dis= min(dis_left,dis_right)。那么一个点在集合A,一个在集合B中的情况,可以针对此情况,用之前分解的标准值,即按照x坐标从小到大排序后的中间点的x坐标作为mid,划分一个[mid−dis,mid+dis]区域,如果存在最小距离点对,必定存在这个区域中。

 

之后只需要根据[mid−dis,mid]左边区域的点来遍历右边区域[mid,mid+dis]的点,即可找到是否存在小于dis距离的点对。

3. 设计

 1 #include<stdio.h>
 2 #include<math.h>
 3 #include<algorithm>
 4 #include<vector>
 5 using namespace std;
 6 const int maxn = 1000 + 10;
 7 struct Point {
 8     int x, y;
 9     Point(int _x = 0, int _y = 0) :x(_x), y(_y) {}
10     bool operator < (const Point& rhs)const {
11         return x < rhs.x;
12     }
13 };
14 int n;
15 bool cmp(struct Point& a, struct Point& b) {     //按照x坐标从小到大排序
16     return a.x < b.x;
17 }
18 bool cmp2(struct Point& a, struct Point& b) { //按照y坐标从小到大排序
19     return a.y < b.y;
20 }
21 double Dis(Point a, Point b) {
22     return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
23 }
24 
25 double ClosestPoint(vector<Point> points, int left, int right) {
26     if (right - left < 2)return 0x3f3f3f3f;
27     if (right - left == 2) {
28         return Dis(points[left], points[right - 1]);
29     }
30     if (right - left == 3) {
31         double d1 = Dis(points[left], points[right - 1]);
32         double d2 = Dis(points[left], points[right - 2]);
33         double d3 = Dis(points[right - 2], points[right - 1]);
34         return min(d1, min(d2, d3));
35     }
36     int mid = (right + left) / 2;
37     int mm = points[mid].x;
38     double dl = ClosestPoint(points, left, mid);  //左边区域最短距离
39     double dr = ClosestPoint(points, mid, right);    //右边区域最短距离
40     double minn = min(dl, dr);
41     vector<Point>v;
42     for (int i = left; i < mid; ++i) {
43         if (mm - points[i].x <= minn)
44             v.push_back(points[i]);
45     }
46     for (int i = mid; i < right; ++i) {
47         if (points[i].x - minn <= mm)
48             v.push_back(points[i]);
49     }
50     sort(v.begin(), v.end(), cmp2);
51     double mindist = 0x3f3f3f3f;
52     for (int i = 0; i < v.size(); ++i) {            //处理分隔线两边的点
53         for (int j = i+1; j < v.size(); ++j) {
54             if (abs(v[i].y - v[j].y) < minn) {
55                 double d = Dis(v[i], v[j]);
56                 if (d < minn) mindist = d;
57             }
58             else {
59                 break;
60             }
61         }
62     }
63     return min(minn, mindist);
64 }
65 
66 int main() {
67     vector<Point>points;
68     scanf("%d", &n);
69     for (int i = 1; i <= n; ++i) {
70         Point point;
71         scanf("%d %d", &point.x, &point.y);
72         points.push_back(point);
73     }
74     sort(points.begin(), points.end(), cmp);
75     printf("%.2f\n", ClosestPoint(points, 0, n));
76 }

4. 分析

因此整体的时间复杂度为O(nlogn)。

5. 源码

https://github.com/JayShao-Xie/algorithm-work/blob/master/ClosestPoint.cpp

猜你喜欢

转载自www.cnblogs.com/JayShao/p/12562431.html