精华内容
下载资源
问答
  • 1. 对于平面上给定的N个点,给出所有点对的最短距离,即,输入是平面上的N个点,输出是N点中具有最短距离的两点。2. 要求随机生成N个点的平面坐标,应用蛮力法编程计算出所有点对的最短距离。3. 要求随机生成N个点的...
  • 分治法—最近点对.cpp

    2020-04-08 19:55:39
    对于短路的你,希望算法代码给你一个新的思路,代码的讲解利于你更好的对于题目的详细解释同时学会方法,利于自身的创新
  • 分治法求最近点对问题,要求:1. 对于平面上给定的N个点,给出所有点对的最短距离,即,输入是平面上的N个点,输出是N点中具有最短距离的两点。 2. 要求随机生成N个点的平面坐标,应用蛮力法编程计算出所有点对的...
  • 1. 对于平面上给定的N个点,给出所有点对的最短距离,即,输入是平面上的N个点,输出是N点中具有最短距离的两点。 2. 要求随机生成N个点的平面坐标,应用蛮力法编程计算出所有点对的最短距离。 3. 要求随机生成N个点...
  • 平面最近点对问题分治算法解答,C++实现,代码整洁规范。
  • 1. 对于平面上给定的N个点,给出所有点对的最短距离,即,输入是平面上的N个点,输出是N点中具有最短距离的两点。2. 要求随机生成N个点的平面坐标,应用蛮力法编程计算出所有点对的最短距离。3. 要求随机生成N个点的...
  • 分别用暴力法和分治法 求解最近点对问题 C++代码 网盘链接
  • 本资源为文档类型,内有相关代码,题目是用分治法解平面最近点对问题,希望有帮助!
  • 最近点对问题

    热门讨论 2012-11-11 18:03:05
    ★问题描述: 给出平面上的 N 个二维点,求出距离最小的 2 个点...输出一个浮点数,表示最近点对的距离除以 2,保留 2 位小数(四舍五入)。 输入示例 2 0 0 1 1 2 1 1 1 1 3 -1.5 0 0 0 0 1.5 0 输出示例 0.71 0.00 0.75
  • 这是算法作业,最近点对问题,采用分治策略。资源内包括全部代码,和exe文件。以文件形式读入所有点的位置,文件在Debug文件夹内和exe文件放在一起。
  • 最近点对,算法中最近点对问题的C++设计与实现。MFC图形化实现界面。
  • 最近点对问题的实现

    2018-03-20 11:51:09
    使用分治的思想,将最近点对问题转化为左右和横跨左右的点对的问题,由左右两个子问题返回左右两边最短的点对距离,设为d,则横跨左右的点对只需要考虑距离分割线水平距离小于d的点,而且对于每个横跨左右的点得搜索...
  • 一共四项实验:大数乘法+最近点对问题+最优二分查找树+所有点的最短路径,详细报告可以参考:http://www.doc88.com/p-1814881556545.html
  • 分治法求最近点对

    2013-10-27 22:17:36
    资源位分治法求最近点对,包含几种算法,以及图形界面,是一套完整的工程。全部为java实现。
  • 使用C++编写的寻找最近点对算法,使用分治法,以矩形范围优化算法效率,使得性能得到最佳
  • 平面最接近点对问题的源代码,使用分治算法
  • 最近点对

    千次阅读 2019-04-27 04:10:10
    设p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n个点构成的集合S,设计算法找出集合S中距离最近点对。 输入 多组测试数据,第一行为测试数据组数n(0<n≤100),每组测试数据由两个部分构成,第一部分...

    传送门最近对问题

    题目描述

    设p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n个点构成的集合S,设计算法找出集合S中距离最近的点对。

    输入

    多组测试数据,第一行为测试数据组数n(0<n≤100),每组测试数据由两个部分构成,第一部分为一个点的个数m(0<m≤1000),紧接着是m行,每行为一个点的坐标x和y,用空格隔开,(0<x,y≤100000)

    输出

    每组测试数据输出一行,为该组数据最近点的距离,保留4为小数。

    样例

    • Input
      2
      2
      0 0
      0 1
      3
      0 0
      1 1
      1 0
    • Output
      1.0000
      1.0000

    思路

    • 按x排序,二分区间,找到左右子区间的最小距离d=min(d1,d2),再在中间[mid-d,mid+d]找是否有更小的
      引用自https://blog.csdn.net/sinat_35678407/article/details/82874216
    • 由鸽巢定理,对于[mid-d,mid]中的某点i,在[mid,mid+d]中最多找6个点就能确定结果
    • 时间复杂度O(nlgnlgn),中间区域按y排序O(nlgn),这一步可以通过归并思想优化到n,总时间复杂度优化至O(nlgn)。

    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
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    #include<bits/stdc++.h>
    #define INIT(a,b) memset(a,b,sizeof(a))
    #define LL long long
    using namespace std;
    const int inf=0x3f3f3f3f;
    const int maxn=1e3+7;
    const int mod=1e9+7;
    struct Node{
    double x,y;
    }node[maxn];
    Node tem[maxn];
    bool cmpX(Node a,Node b){return a.x<b.x;}
    bool cmpY(Node a,Node b){return a.y<b.y;}
    double Dis(Node a,Node b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
    double MinDis(int l,int r){
    int len=r-l+1;
    if(len==2) return Dis(node[l],node[r]);
    if(len==3) return min(Dis(node[l],node[l+1]),Dis(node[l+1],node[r]));
    int mid=(l+r)>>1;
    double d=min(MinDis(l,mid),MinDis(mid+1,r));
    int tot=0;
    for(int i=l;i<=r;i++){
    if(fabs(node[i].x-node[mid].x<=d))
    tem[tot++]=node[i];
    }
    sort(tem,tem+tot,cmpY);
    for(int i=0;i<tot;i++){
    for(int j=i+1;j<i+6 && j<tot;j++){
    d=min(d,Dis(tem[i],tem[j]));
    }
    }
    return d;
    }
    int main(){
    //freopen("0.in","r",stdin);
    int t,n;
    while(~scanf("%d",&t)){
    while(t--){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%lf%lf",&node[i].x,&node[i].y);
    sort(node+1,node+1+n,cmpX);
    printf("%.4lf\n",MinDis(1,n));
    }
    }
    return 0;
    }
    展开全文
  • 分别用暴力法和递归方法实现了最近点对的计算,并且带有图形界面!
  • 最近点对问题(python实现)

    千次阅读 2020-10-11 21:45:23
    最近用python比较多,想要用python写出一个最近点对查询算法,结果网上找不到,于是自己写了一个,发在这里是供自己以后参考,也是与大家共享,具体思路已经写在代码里,自测是通过的,如果有什么问题,希望大家能够...

    最近用python比较多,想要用python写出一个最近点对查询算法,结果网上找不到,于是自己写了一个,发在这里是供自己以后参考,也是与大家共享,具体思路已经写在代码里,自测是通过的,如果有什么问题,希望大家能够指出来。

    '''
    最小点对算法:给定平面上n个点,找其中的一对点,使得在n个点的所有点对中,该点对的距离最小。严格地说,最接近点对可能多于1对。为了简单起见,这里只限于找其中的一对。
    主要算法思想:先把所有点按照x值排序,从最中间(x值中位数b)将所有点分为三个部分,左子域(左子域包括中间子域)、右子域、x值恰好等于中位数的中间子域,分别找出左右子域中的最近点,取最小值为d,
    再将左右子域的x值范围缩减到[b-d,b+d]之间,循环遍历左子域中的每个点,在右子域中寻找y值离当前点最近的四个点,分别求距离,取最小距离,然后寻找中间子域中的最近点,取最小距离
    通过递归(分治)的方法,最终正确查找到最近点对
    '''
    import math
    # 输入
    p = [[0,0], [1,1],[3,4],[0,3],[3.2, 4.2], [0,-1],[-2,-2],[-1,-2],[0, 0.4], [-1,2],[0,2],[0.5,2]]
    # p = [[0,0], [1,1], [3,4]]
    n = len(p)
    # 预期输出:最近点对是 ( 3.2 , 4.2 ) 和 ( 3 , 4 ), 最短距离为 0.2828427124746193
    
    # 查找最接近的目标的y下标
    def find_closed_index(collections, target):
        n = len(collections)
        low = 0
        high = n - 1
        mid = 0
        while low <= high:
            mid = math.floor((low + high) / 2)
            if target > collections[mid][1]:
                low = mid + 1
            elif target < collections[mid][1]:
                high = mid - 1
            else:
                return mid
    
        return mid
    
    def distance(p1, p2):
        return math.sqrt(pow(p1[0] - p2[0], 2) + pow(p1[1] - p2[1], 2))
    
    def divide(l, r, res):
        if l == r:
            return float("inf"), []
        if (l + 1) == r:
            return distance(p[l], p[r]), [p[l], p[r]]
        mid = math.floor((l + r) / 2)
        d1, res1 = divide(l, mid, res)
        d2, res2 = divide(mid + 1, r, res)
        if d1 >= d2:
            d = d2
            res = res2
        else:
            d = d1
            res = res1
    
        # 先将所有左子域、右子域、同一x值的中间子域,删选出来
        left = []
        right = []
        midd = []
        b = p[mid][0]
        bl = b - d
        br = b + d
        for i in range(n):
            if ((p[i][0] >= bl) & (p[i][0] <= b)) == True:
                left.append(p[i])
                if p[i][0] == b:
                    midd.append(p[i])
            elif ((p[i][0] <= br) & (p[i][0] >= b)) == True:
                right.append(p[i])
    
    
        if len(right) == 0:
            return d, res
    
        # 将右子域先按照y值大小排好序
        right.sort(key=lambda x:x[1])
    
        # 遍历左子域中的每一个点,在右子域中寻找y值最邻近的四个点,求出最小距离以及最近点对
        for i in range(len(left)):
            closed_point = []
            right_num = len(right)
            if right_num <= 4:
                closed_point = right
            else:
                index = find_closed_index(right, left[i][1])
                if index >= 4:
                    start = index - 4
                else:
                    start = 0
                if index + 5 > len(right) - 1:
                    end = len(right) - 1
                else:
                    end = index + 5
    
                for j in range(start, end):
                        closed_point.append(right[j])
    
                # 前四个就是右子域中离左子域最近的四个点
                closed_point.sort(key=lambda x: abs(x[1] - left[i][1]))
    
            if len(closed_point) >= 4:
                end2 = 4
            else:
                end2 = len(closed_point)
    
            for k in range(0, end2):
                dist = distance(closed_point[k], left[i])
                if dist < d:
                    res = [closed_point[k], left[i]]
                    d = dist
    
        # 再在中间子域的内部进行比较,看看有没有x值相同,且距离最近的两个点
        if len(midd) > 1:
            midd.sort()
            for j in range(len(midd) - 1):
                dist = distance(midd[j], midd[j + 1])
                if dist < d:
                    res = [midd[j], midd[j + 1]]
                    d = dist
    
        return d, res
    
    # 前期需要按照x值排序
    p.sort()
    d, res = divide(0, n-1, [])
    print("最近点对是 (", res[0][0], ",", res[0][1], ") 和 (", res[1][0], ",", res[1][1], "), 最短距离为", d)

    展开全文
  • 求解平面上二维点对的最近距离,并返回这个最近点对,非常经典的代码
  • 分治——最近点对问题

    万次阅读 多人点赞 2018-09-28 15:55:04
    利用分治方法的经典问题——最近点对问题(Closest pair of points problem) 问题描述 n个点在公共空间中,求出所有点对的欧几里得距离最小的点对。 问题分析 该题直观的解决方法便是Brute Force(暴力求解)...

    利用分治方法的经典问题——最近点对问题(Closest pair of points problem)

    问题描述

    n个点在公共空间中,求出所有点对的欧几里得距离最小的点对。
    最近点对

    问题分析

    • 该题直观的解决方法便是Brute Force(暴力求解)。时间复杂度为 O ( n 2 ) O(n^2) On2
    minDist = infinity
    for i = 1 to length(P) - 1
     for j = i + 1 to length(P)
      let p = P[i], q = P[j]
      if dist(p, q) < minDist:
       minDist = dist(p, q)
       closestPair = (p, q)
    return closestPair
    
    • 利用分治思想进行求解。首先分析题目,符合分治法的适用条件,规模越小容易求解,同时具有最优子结构。

    分治法求解

    • 分解
      • 对所有的点按照x坐标(或者y)从小到大排序(排序方法时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn))。
      • 根据下标进行分割,使得点集分为两个集合。
    • 解决
      • 递归的寻找两个集合中的最近点对。
      • 取两个集合最近点对中的最小值 m i n ( d i s l e f t , d i s r i g h t ) min(dis_{left}, dis_{right}) min(disleftdisright)
    • 合并
      • 最近距离不一定存在于两个集合中,可能一个点在集合A,一个点在集合B,而这两点间距离小于dis。

    这其中如何合并是关键。根据递归的方法可以计算出划分的两个子集中所有点对的最小距离 d i s l e f t , d i s r i g h t dis_{left}, dis_{right} disleftdisright,再比较两者取最小值,即 d i s = m i n ( d i s l e f t , d i s r i g h t ) dis = min(dis_{left}, dis_{right}) dis=min(disleftdisright)。那么一个点在集合A,一个在集合B中的情况,可以针对此情况,用之前分解的标准值,即按照x坐标(或者y)从小到大排序后的中间点的x坐标作为mid,划分一个 [ m i d − d i s , m i d + d i s ] [mid - dis, mid + dis] [middis,mid+dis]区域,如果存在最小距离点对,必定存在这个区域中。
    merge
    之后只需要根据 [ m i d − d i s , m i d ] [mid - dis, mid] [middis,mid]左边区域的点来遍历右边区域 [ m i d , m i d + d i s ] [mid, mid + dis] [mid,mid+dis]的点,即可找到是否存在小于dis距离的点对。
    但是存在一个最坏情况,即通过左右两个区域计算得到的dis距离来划分的第三区域可能包含集合所有的点,这时候进行遍历查找,时间复杂度仍然和brute force方法相同,都为 O ( n 2 ) O(n^2) O(n2)。因此需要对此进行深一步的考虑。
    1985年Preparata和Shamos在给出该问题的一个分治算法并且还具体分析了在 [ m i d − d i s , m i d + d i s ] [mid - dis, mid + dis] [middis,mid+dis]区域中出现的情况,若(p,q)是Q的最近点对,p在带域左半部分,则q点必在下图所示的 δ ∗ 2 δ \delta *2\delta δ2δ长方形上,而在该长方形上,最多只能由右边点集的6个点。每个点对之间的距离不小于 δ \delta δ
    6
    此结论很好证明,通过在 δ ∗ 2 δ \delta *2\delta δ2δ上以 2 δ 3 ∗ δ 2 \frac{2\delta}{3} *\frac{\delta}{2} 32δ2δ划成6个小长方形
    6point
    用反证法来证明,假设存在大于6个点,则必有一个或多个小长方形存在两个及以上点,而小长方形的最长距离是为对角线长度,为: s q r t ( 2 δ 3 ∗ 2 δ 3 + δ 2 ∗ δ 2 ) = 5 δ 6 &lt; δ sqrt(\frac{2\delta}{3} *\frac{2\delta}{3} + \frac{\delta}{2}*\frac{\delta}{2}) = \frac{5\delta}{6} &lt; \delta sqrt(32δ32δ+2δ2δ)=65δ<δ。最长距离都小于 δ \delta δ,与之前的条件不符合,故最多有6个点。借此,可以将可能的线性时间缩小到常数级,大大提高了平均时间复杂度。
    1998年,由周玉林、熊鹏荣、朱洪教授提出了平面最近点对的一个改进算法,针对Preparata-Shamos算法提出的6个点,又证明其实只需要4个点就可以确定最近点对距离,该证明提出2个定理,利用更加准确的半径画圈,证明了只要对左半域上的每个点p,检验右半域y坐标与p最近的至多4个点即可(上下个两个)。具体证明可以参考《求平面点集最近点对的一个改进算法》。
    根据以上的优化,可以在合并时,通过检测与左半域点p的y坐标相邻的2个或者3个,即使用4点或者6点来检测,一般为了省事,只求与p点y坐标上界或者下界右半域连续的6个、4个点即可。

    时间复杂度

    在分解和合并时,可能存在按照x轴、y轴进行排序的预处理 O ( n l o g n ) O(nlogn) O(nlogn),该问题在解决阶段只做提取的操作为 Θ ( n ) Θ(n) Θ(n),递推式为:
    T ( n ) = { 1 n &lt; = 3 2 T ( n 2 ) + O ( n ) n &gt; 3 T(n) = \begin{cases} 1 &amp; n &lt;= 3 \\ 2T(\frac{n}{2}) + O(n) &amp; n &gt; 3 \end{cases} T(n)={12T(2n)+O(n)n<=3n>3
    计算后得到整体时间复杂度为: O ( n l o g n ) O(nlogn) O(nlogn)

    代码实现

    struct point {
    	double x;
    	double y;
    	point(double x, double y) :x(x), y(y) {}
    	point() { return; }
    };
    
    bool cmp_x(const point & A, const point & B)  // 比较x坐标
    {
    	return A.x < B.x;
    }
    
    bool cmp_y(const point & A, const point & B)  // 比较y坐标
    {
    	return A.y < B.y;
    }
    
    double distance(const point & A, const point & B)
    {
    	return sqrt(pow(A.x - B.x, 2) + pow(A.y - B.y, 2));
    }
    /*
    * function: 合并,同第三区域最近点距离比较
    * param: points 点的集合
    *        dis 左右两边集合的最近点距离
    *        mid x坐标排序后,点集合中中间点的索引值
    */
    double merge(vector<point> & points, double dis, int mid)
    {
    	vector<point> left, right;
    	for (int i = 0; i < points.size(); ++i)  // 搜集左右两边符合条件的点
    	{
    		if (points[i].x - points[mid].x <= 0 && points[i].x - points[mid].x > -dis)
    			left.push_back(points[i]);
    		else if (points[i].x - points[mid].x > 0 && points[i].x - points[mid].x < dis)
    			right.push_back(points[i]);
    	}
    	sort(right.begin(), right.end(), cmp_y);
    	for (int i = 0, index; i < left.size(); ++i)  // 遍历左边的点集合,与右边符合条件的计算距离
    	{
    		for (index = 0; index < right.size() && left[i].y < right[index].y; ++index);
    		for (int j = 0; j < 7 && index + j < right.size(); ++j)  // 遍历右边坐标上界的6个点
    		{
    			if (distance(left[i], right[j + index]) < dis)
    				dis = distance(left[i], right[j + index]);
    		}
    	}
    	return dis;
    }
    
    
    double closest(vector<point> & points)
    {
    	if (points.size() == 2) return distance(points[0], points[1]);  // 两个点
    	if (points.size() == 3) return min(distance(points[0], points[1]), min(distance(points[0], points[2]), 
    		distance(points[1], points[2])));  // 三个点
    	int mid = (points.size() >> 1) - 1;
    	double d1, d2, d;
    	vector<point> left(mid + 1), right(points.size() - mid - 1);
    	copy(points.begin(), points.begin() + mid + 1, left.begin());  // 左边区域点集合
    	copy(points.begin() + mid + 1, points.end(), right.begin());  // 右边区域点集合
    	d1 = closest(left);
    	d2 = closest(right);
    	d = min(d1, d2);
    	return merge(points, d, mid);
    }
    
    int main()
    {
    	int count;
    	printf("点个数:");
    	scanf("%d", &count);
    	vector<point> points;
    	double x, y;
    	for (int i = 0; i < count; ++i)
    	{
    		printf("第%d个点", i);
    		scanf("%lf%lf", &x, &y);
    		point p(x, y);
    		points.push_back(p);
    	}
    	sort(points.begin(), points.end(), cmp_x);
    	printf("最近点对值:%lf", closest(points));
    	return 0;
    }```
    
    展开全文
  • c++ 最近点对问题

    2010-12-05 15:18:38
    c++ 最近点对问题
  • 【算法设计与分析】分治法与最近点对问题

    千次阅读 多人点赞 2018-10-15 17:26:32
    说明:这是武汉理工大学计算机学院【算法设计与分析】课程的第一次实验第三题:分治法与最近点对问题 >>点击查看WUTer计算机专业实验汇总 谨记:纸上得来终觉浅,绝知此事要躬行。 一、问题描述 设,,…...

    一、问题描述

    p_{1}=(x_{1},y_{1})p_{2}=(x_{2},y_{2}),…,p_{n}=(x_{n},y_{n})是平面上n个点构成的集合S,最近对问题就是找出集合S中距离最近的点对。

    严格地讲,最接近点对可能多于一对,简单起见,只找出其中的一对作为问题的解。

    二、问题分析

    用分治法解决最近对问题,很自然的想法就是将集合S分成两个子集 S_{1}S_{2},每个子集中有n/2个点。然后在每个子集中递归地求其最接近的点对,在求出每个子集的最接近点对后,在合并步中,如果集合 S 中最接近的两个点都在子集 S_{1}S_{2}中,则问题很容易解决,如果这两个点分别在 S_{1}S_{2}中,问题就比较复杂了。

    最近对问题的分治策略是:

    划分将集合S分成两个子集S_{1}S_{2},设集合S的最近点对是p_{i}p_{j}1\leq i,j\leq n,则会出现以下三种情况:

    求解子问题对于划分阶段的情况①和②可递归求解,如果最近点对分别在集合S1S2中,问题就比较复杂了。

    合并比较在划分阶段三种情况下最近点对,取三者之中较小者为原问题的解。

    为了使问题易于理解,先考虑一维的情形。

    此时,S中的点退化为x轴上的n个点x1, x2, …, xn。用x轴上的某个点mS划分为两个集合S1S2,并且S1S2含有点的个数相同。递归地在S1S2上求出最接近点对 (p1, p2) (q1, q2),如果集合S中的最接近点对都在子集S1S2中,则d=min{(p1, p2), (q1, q2)}即为所求,如果集合S中的最接近点对分别在S1S2中,则一定是(p3, q3)其中,p3是子集S1中的最大值,q3是子集S2中的最小值。

    下面考虑二维的情形,此时S中的点为平面上的点。

    关键点1:分割点M的选取问题

    仍以一维为例:选取分割点m的一个基本要求是由此导出集合S的一个线性分割,即S=S1∪S2 S1∩S2,且S1={x|x≤m}S2={x|x>m}。容易看出,一维情况下,如选m=[max(S)+min(S)]/2,可以满足线性分割的要求。选取分割点后,再用O(n)时间即可将S划分成S1={x∈S|x≤m}S2={x∈S|x>m}。然而,这样选取分割点m有可能造成划分出的子集S1S2的不平衡

    例如在最坏情况下,|S1|=1|S2|=n-1,由此产生的分治法在最坏情况下所需的计算时间T(n)应满足递归方程:

      T(n)=T(n-1)+O(n)    它的解是T(n)=O(n2)

    这种效率降低现象可通过分治法中“平衡子问题”方法加以解决。即通过适当选择分割点m,使S1S2中有大致相等个数的点。

    因此,用Sn个点的坐标的中位数来作分割点。在选择算法中介绍的选取中位数的线性时间算法使我们可以在O(n)时间内确定一个平衡的分割点m

    以上情况可以方便推广到二维,即二维情况下,mS中各点x坐标的中位数。—中位数是指将数据按大小顺序排列起来,形成一个数列,居于数列中间位置的那个数据。

    关键点2:情况的求解

    为了将平面上的点集S 分割为点的个数大致相同的两个子集S1S2,选取垂直线x=m来作为分割线,其中,mS中各点x坐标的中位数。由此将S分割为S1={pS | xpm}S2={qS | xqm}。递归地在S1S2上求解最近对问题,分别得到S1中的最近距离d1S2中的最近距离d2,令d=min(d1, d2),若S的最近对(p, q)之间的距离小于d,则pq必分属于S1S2,不妨设pS1qS2,则pq距直线x=m的距离均小于d(否则就p,q的距离就大于d),所以,可以将求解限制在以x=m为中心、宽度为2d的垂直带P1P2中,垂直带之外的任何点对之间的距离都一定大于d

    假设p(x,y)P1P2y坐标最小的点,由于p 可能在P1P2,所以需要找与p距离小于d的点,显然,这样点的y轴坐标一定位于区间[y, y+d]之间,而且,这样的点不会超过8个(鸽笼原理可以证明P1P2 分别为4)。---如果超过了8个,例如9个,那么必有2两个点距离小于d

    处理方法:将P1P2中的点按y的升序排列,顺序处理P1P2中的点p(x,y),y坐标区间中最多取8个点,计算其与点p 的距离。

    三、算法设计

    四、实验代码

    完整VS2017项目:https://github.com/cxh1231/Junior-Algorithm-ClosestPointProblem

    #include <iostream>
    #include <math.h>
    using namespace std;
    
    const int n = 8;
    
    //定义结构体表示集合S中的 点的坐标
    struct point{
    	int x, y;
    };
    
    double Closest(point S[], int low, int high);		//实现求最近对距离
    double Distance(point a, point b);					//求两点之间距离
    int Partition(point r[], int first, int end);		//划分【课本P62】
    void QuickSort(point r[], int first, int end);		//快速排序【课本P63】
    
    //实现求最近对距离
    double Closest(point S[], int low, int high){
    	double d1, d2, d3, d;
    	int mid, i, j, index;
    	point P[n];                   //存放点集合 P1和P2
    
    	//如果只有两个点,返回这两个点间的距离
    	if (high - low == 1) {
    		return Distance(S[low], S[high]);
    	}
    
    	//如果有三个点,求最近点对距离
    	if (high - low == 2)	{
    		d1 = Distance(S[low], S[low + 1]);
    		d2 = Distance(S[low + 1], S[high]);
    		d3 = Distance(S[low], S[high]);
    		if ((d1 < d2) && (d1 < d3))	return d1;
    		else if (d2 < d3) return d2;
    		else return d3;
    	}
    
    	mid = (low + high) / 2;				//计算中间点
    	d1 = Closest(S, low, mid);			//递归求解子问题①
    	d2 = Closest(S, mid + 1, high);		//递归求解子问题②
    
    	if (d1 <= d2) d = d1;				//已下为求解子问题③
    	else d = d2;
    	index = 0;
    	for (i = mid; (i >= low) && (S[mid].x - S[i].x < d); i--)			//建立点集合P1
    		P[index++] = S[i];
    	for (i = mid + 1; (i <= high) && (S[i].x - S[mid].x < d); i++)		//建立点集合P2
    		P[index++] = S[i];
    
    	//对集合P1、P2按y坐标升序排列
    	QuickSort(P, 0, index - 1);
    	
    	//依次处理集合P1和P2中的点
    	for (i = 0; i < index; i++)	{
    		for (j = i + 1; j < index; j++)		{
    			if (P[j].y - P[i].y >= d)		//超出y坐标的范围,点P[i]处理完毕
    				break;
    			else			{
    				d3 = Distance(P[i], P[j]);
    				if (d3 < d)
    					d = d3;
    			}
    		}
    	}
    	return d;
    }
    
    //求两点之间距离
    double Distance(point a, point b){
    	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }
    
    //划分【课本P62】
    int Partition(point r[], int first, int end){				//划分
    	int i = first, j = end;									//初始化待划分区间
    	while (i < j)	{
    		while (i < j && r[i].y <= r[j].y) j--;				//右侧扫描
    		if (i < j) {
    			point temp = r[i]; r[i] = r[j]; r[j] = temp;	//将较小记录交换到前面
    			i++;
    		}
    		while (i < j && r[i].y <= r[j].y) i++;				//左侧扫描
    		if (i < j) {
    			point temp = r[i]; r[i] = r[j]; r[j] = temp;    //将较大记录交换到后面
    			j--;
    		}
    	}
    	return i;												// 返回轴值记录的位置
    }
    
    //快速排序【课本P63】
    void QuickSort(point r[], int first, int end){  //快速排序
    	int pivot;
    	if (first < end) {
    		pivot = Partition(r, first, end);		//划分,pivot是轴值在序列中的位置
    		QuickSort(r, first, pivot - 1);			//求解子问题1,对左侧子序列进行快速排序
    		QuickSort(r, pivot + 1, end);			//求解子问题2,对右侧子序列进行快速排序
    	}
    }
    
    
    int main()
    {
    	//输入按x坐标升序排列的n个点的集合
    	point S[n] = { {1,4},{1,8},{2,1},{3,2},{4,4},{5,1},{6,6},{7,2} };
    	double minDist = Closest(S, 0, n - 1);
    	//输出最近点对的距离
    	cout << "最近点对距离为:"<< minDist << endl;
    	return 0;
    }

    五、运行结果

    最近点对距离为:1.414……

    六、总结

    T(n)=O(nlog2n)

    展开全文
  • 分治法详解二维最近点对问题

    千次阅读 多人点赞 2020-04-14 16:47:31
    算法设计与分析——分治法:详解二维最近点对问题1 前言2 问题描述3 分治法4 暴力求解4.1 算法思路4.2 时间复杂度分析4.3 代码实现5 分治法求解5.1 算法思路5.1.1 数据预处理5.1.2 划分中轴线5.1.3 求半边最小距离...
  • c语言 最近点对问题(分治法+递归)

    千次阅读 热门讨论 2019-07-14 21:26:28
    就是在一条直线上,寻找最近点对的距离,这个我们其实可以进行直接的循环比较,简单说来就是先拿一个点,让它与其他(n-1)个点计算距离,每次比较存储最小即可。但这样效率太低了,时间复杂度分分钟都到O(n^2)上去...
  • 3.不断细分,找出左右两部分的最近点对 4.重复步骤1.2.3,得到最终左右两部分的最近点对的距离d 5.找出 |X - Xmid| < d ,部分的点对,此部分左边的点对集合我们设为p1,右边设为p2,对p1,p2中的点按y的大小从小到...
  • 寻找最近点对

    千次阅读 2016-08-11 23:03:49
    显然,寻找最近点对最原始的算法是计算所有的点对的距离来找出最近点对。这种算法依赖n的值,n的值越大运行时间越长。为了提高时效,可应用分治算法解决。 算法每次递归调用的输入为点的自集P和数组Y。P中的所有点按...
  • java实现分治法寻找最近点对

    热门讨论 2009-10-25 11:47:25
    使用java编写 用分治法实现对于平面上最近点对的查找 使用Swing作为界面
  • C++最近点对问题,蛮力算法和分治算法,分治法:遵循分治思路方法利用递归求出左子集和右子集最近点对然后再对两子集的间点对进步分析比较最后求出整个点集最近点对
  • 最近点对问题(分治法)

    千次阅读 多人点赞 2020-04-23 16:46:56
    给定平面S上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小 蛮力法求解 点的存储: class Point{ //横坐标 int x; //纵坐标 int y; /** * 求解两个坐标之间的距离 * ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 945,122
精华内容 378,048
关键字:

最近点对