给定平面上的N个点,寻找距离最远的两个点

本文介绍了凸包算法和卡壳算法的实现方法,并通过C++代码示例展示了如何求解点集的凸包及利用卡壳算法找到凸包直径。

原文链接 http://blog.youkuaiyun.com/wangyangkobe/article/details/6081975


主要是凸包算法、卡壳算法

http://blog.youkuaiyun.com/kaytowin/archive/2010/01/06/5140111.aspx

http://www.cppblog.com/staryjy/archive/2010/09/25/101412.html

http://www.cnblogs.com/devymex/archive/2010/08/09/1795392.html

http://iamhuiam.blog.sohu.com/132378792.html

 

 

 

 

[cpp]  view plain copy
  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. #include <vector>  
  4. #include <stack>  
  5. #include <algorithm>  
  6. #include <iterator>  
  7. #include <cmath>  
  8. using namespace std;  
  9. class Point  
  10. {  
  11. public:  
  12.     Point(){}  
  13.     Point(int m_x, int m_y):x(m_x),y(m_y){}  
  14.     int x;  
  15.     int y;  
  16.     friend ostream& operator<< (ostream &out, const Point &point);  
  17. };  
  18. /************************************************************************/  
  19. /* 函数功能:比较两个点(先以y坐标比较,若y相同按x比较)        */  
  20. /************************************************************************/  
  21. bool Cmp(const Point &left, const Point &right)  
  22. {  
  23.     return ((left.y < right.y) || ((left.y == right.y) && (left.x < right.x)));  
  24. }  
  25. /************************************************************************/  
  26. /* 函数功能:求两个向量的内积                                  */  
  27. /************************************************************************/  
  28. int CrossProduct(const Point &pre, const Point &cur, const Point &next)//pre是上一个点,cur是当前点,next是将要选择的点   
  29. {  
  30.     int x1 = cur.x - pre.x;  
  31.     int y1 = cur.y - pre.y;  
  32.     int x2 = cur.x - next.x;  
  33.     int y2 = cur.y - next.y;  
  34.     return (x1*x2 + y1*y2); //<0是满足凸包的点  
  35. }  
  36. ostream& operator<< (ostream &out, const Point &point)  
  37. {  
  38.     out<<"("<<point.x<<","<<point.y<<")";  
  39.     return out;  
  40. }  
  41. /************************************************************************/  
  42. /* 函数功能:求两点间的距离                                    */  
  43. /************************************************************************/  
  44. int Distance(const Point &point1, const Point &point2)  
  45. {  
  46.     return (point1.x - point2.x)*(point1.x - point2.x) + (point1.y - point2.y)*(point1.y - point2.y);  
  47. }  
  48. /************************************************************************/  
  49. /* 函数功能:获取凸包 
  50.    参数vec存放输入的点,result存放凸包上的点*/  
  51. /************************************************************************/  
  52. void GetConvexHull(vector<Point> vec, vector<Point> &result)  
  53. {  
  54.     sort(vec.begin(), vec.end(), Cmp); //排序  
  55.     int size = vec.size();  
  56.     if(size < 3)  
  57.     {  
  58.         copy(vec.begin(), vec.end(), back_inserter(result));  
  59.     }  
  60.     else  
  61.     {  
  62.         result.push_back(vec.at(0));  
  63.         result.push_back(vec.at(1));  
  64.         result.push_back(vec.at(2));  
  65.         int top = 2;  
  66.         for(int i=3; i<size; i++)  
  67.         {  
  68.             while((top>0) && (CrossProduct(result.at(top-1), result.at(top), vec.at(i)) >= 0))  
  69.             {  
  70.                 result.pop_back();  
  71.                 top--;  
  72.             }  
  73.             result.push_back(vec.at(i));  
  74.             top++;  
  75.         }  
  76.     }  
  77. }  
  78. /************************************************************************/  
  79. /* 函数功能:卡壳算法(我也没搞懂)                             */  
  80. /************************************************************************/  
  81. int RotatingCalipers(vector<Point> vec, int n)  
  82. {  
  83.     int j = 1;  
  84.     int maxLength = 0;//存储最大值  
  85.     vec[n] = vec[0];  
  86.     for(int i = 0; i<n; i++)  
  87.     {  
  88.         while(CrossProduct(vec[i+1], vec[j+1], vec[i]) > CrossProduct(vec[i+1], vec[j], vec[i]))  
  89.             j = (j+1)%n;  
  90.         maxLength = max(maxLength, max(Distance(vec[i], vec[j]), Distance(vec[i+1], vec[j+1])));              
  91.     }  
  92.     return maxLength;   
  93. }  
  94. int main()  
  95. {  
  96.     vector<Point> vec;  
  97.     const int N = 20;  
  98.     for(int i=0; i<N; i++)  
  99.     {  
  100.         vec.push_back(Point(rand()%30, rand()%30));  
  101.     }  
  102.     cout<<"平面上的点:"<<endl;  
  103.     copy(vec.begin(), vec.end(), ostream_iterator<Point>(cout, "/n"));  
  104.     cout<<endl;  
  105.     vector<Point> result;  
  106.     GetConvexHull(vec, result);  
  107.       
  108.     cout<<"凸包上的点:"<<endl;  
  109.     copy(result.begin(), result.end(), ostream_iterator<Point>(cout, " "));  
  110.     cout<<endl;  
  111.     int distace = RotatingCalipers(result, result.size()-1);  
  112.     cout<<sqrt(double(distace))<<endl;  
  113. }  

使用分治算法解决二维平面上 $n$ 个中找出距离最近两的问题,基本思路是将问题分解为子问题,再合并子问题的解得到最终结果。 首先,将平面上的集 $P$ 按 $x$ 坐标排序,做一条垂直线 $l$ 把集近似划分为大小相等的两个子集 $P_L$ 和 $P_R$。最邻近对有三种情况:都在 $P_L$ 中、都在 $P_R$ 中、一个在 $P_L$ 中一个在 $P_R$ 中。 对于前两种情况,分别递归计算 $P_L$ 和 $P_R$ 中的最邻近距离,这是两个规模为 $n/2$ 的子问题。假设 $P_L$ 和 $P_R$ 中的最邻近距离分别是 $d_L$ 和 $d_R$,令 $d = \min(d_L, d_R)$。 对于第三种情况,只需要寻找垂直线 $l$ 两边距 $l$ 不超过 $d$ 的窄缝内的。对于在线 $l$ 左边距离 $d$ 范围内的每个,检查 $l$ 右边是否有与它的距离小于 $d$,如果存在则将 $d$ 修改为新值。 以下是使用 Python 实现的代码: ```python import math def distance(p1, p2): return math.sqrt((p1[0] - p2[0])**2 + (p1[1] - p2[1])**2) def brute_force(points): min_dist = float('inf') for i in range(len(points)): for j in range(i + 1, len(points)): dist = distance(points[i], points[j]) if dist < min_dist: min_dist = dist return min_dist def closest_pair(points): n = len(points) if n <= 3: return brute_force(points) mid = n // 2 mid_point = points[mid] left_points = points[:mid] right_points = points[mid:] d_left = closest_pair(left_points) d_right = closest_pair(right_points) d = min(d_left, d_right) strip = [] for point in points: if abs(point[0] - mid_point[0]) < d: strip.append(point) strip.sort(key=lambda point: point[1]) for i in range(len(strip)): for j in range(i + 1, min(i + 7, len(strip))): dist = distance(strip[i], strip[j]) if dist < d: d = dist return d # 示例使用 points = [(2, 3), (12, 30), (40, 50), (5, 1), (12, 10), (3, 4)] points.sort() min_distance = closest_pair(points) print("最近两距离是:", min_distance) ``` ### 代码解释: 1. **`distance` 函数**:计算两之间的欧几里得距离。 2. **`brute_force` 函数**:当的数量小于等于 3 时,使用暴力法计算最小距离。 3. **`closest_pair` 函数**: - 若的数量小于等于 3,调用 `brute_force` 函数。 - 按 $x$ 坐标排序后,将集划分为左右两部分。 - 递归计算左右两部分的最小距离 $d_L$ 和 $d_R$,取最小值 $d$。 - 找出距离分割线不超过 $d$ 的集 `strip`。 - 对 `strip` 按 $y$ 坐标排序,检查窄缝内的对,更新最小距离。 ### 复杂度分析: - **时间复杂度**:$O(n \log n)$。 - **空间复杂度**:$O(n)$。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值