平面最近点对问题求解

C++用蛮力法与分治法解决最近对问题 设 p1(x1,y1),p2(x2,y2),……,pn(xn,yn)是平面上n个点构成的集合S,最近对问题就是找出集合S中距离最近的点对。严格地讲,最接近点对可能多于一对,简单起见,只找出其中的一对即可。 阅读详情

平面最近点对问题求解

问题描述:

最近点对问题是指求解平面点集n个点中距离最近的两个点间的问题。为简单起见,在二维坐标平面来考虑该问题。如果说讨论的点以标准二维坐标给出,则有点这里写图片描述和这里写图片描述,那么这两点之间的距离这里写图片描述。通过这个公式,我们可以计算平面上任意两点之间的距离。


本章主要通过两种方法来求解

  1. 蛮力法
  2. 分治法

1.蛮力法

顾名思义,蛮力法指的就是通过遍历所有解之后通过对比求出最近点对问题。
基本思路:

对平面中的n个点两两进行组队,计算并记录最小距离。这里需要注意两个问题,其一,点对之间的距离是没有方向性的,即dis( Pi , Pj )=dis,( Pj , Pi ),所以任意两点只需要计算一次即可。其二,计算的时候如果只是求解大小,可以不同开方,这样有一定的优化,简化了公式的计算。

这里以杭电ACM 1007作为例子,蛮力法代码如下:
(由于是蛮力法,所以时间复杂度很高,无法AC1007,这里只是作为例子讲解)
题目链接:杭电ACM 1007

#include "stdio.h"
#include "math.h"
double Point[100001][2];
int main()
{

  int N,a=0,b=0,i,j;
  double Min;
  while(scanf_s("%d",&N) && N!=0)
  {
     Min=9999999;
     for(i=0;i<N;i++)
         scanf_s("%lf%lf",&Point[i][0],&Point[i][1]);
     for(i=0;i<N-1;i++) //N-1
     {
       for(j=i+1;j<N;j++)//这里可以避免对同一对坐标计算两次距离
       {
          double  dis=(Point[j][1]-Point[i][1])*(Point[j][1]-Point[i][1])+
                (Point[j][0]-Point[i][0])*(Point[j][0]-Point[i][0]);
          if(dis<Min)
          {
              Min=dis;
              a=i;  
              b=j;  
          }
       }
     }
     double dis=sqrt((Point[b][1]-Point[a][1])*(Point[b][1]-Point[a][1])+
          (Point[b][0]-Point[a][0])*(Point[b][0]-Point[a][0]));
     printf("%.2lf\n",dis/2);
  }
  return 0;
}

2.分治法

分治法思路:
1) 把它分成两个或多个更小的问题;
2) 分别解决每个小问题;
3) 把各小问题的解答组合起来,即可得到原问题的解答。小问题通常与原问题相似,可以递归地使用分而治之策略来解决。

这里的分治算法的主要思路是将平面上的n个点分为两个子集S1,S2。每个子集中有n/2个点,然后递归的在每个子集中求解最近点对,两边求得的结果如图所示:

这里写图片描述

那么可以看出左边的最近点对的距离为d1,右边为d2.但是最近对可能一个点在S1中而另一个点在S2中。这样,我们,就要去想办法对其进行合并,然后求得合并区域的最近对距离,假设为d3,那么只需要比较d1,d2,d3的大小关系即可,最小的就是平面最近对的距离。通过分析我们可以知道,如果存在这样的最近对的点,那么这个点在S1集合中,肯定是横坐标最靠近中位线 L 的点,S2中同理。那么这个范围如何划定呢?


设d=min(d1,d2)假定中位线横坐标为X,那么范围就是[X-d,X+d].这个范围是怎么划定的呢?根据平面中点的位置我们就可以知道,两点的距离为横纵坐标之间的差值的平方和。那么如果要存在这样的点,他们之间的横坐标之间的差值的绝对值必须要小于等于d(这里包括这点恰好就在中位线 L 上)。这样可以筛选出横坐标为[X-d,X+d]的区域。如下图所示:


这里写图片描述

可以看出这个区域中包含三个点,只需要求出这三个点之间的最近点对即可(蛮力法)。这里还需要注意一点,上面是通过横坐标筛选的这个区域,这里可以根据纵坐标将纵坐标差的绝对值大于 d 的坐标剔除。

这里是分治法求解代码:

#include "stdio.h"
#include "math.h"
#include <cstdio>  
#include "algorithm"
#define MAX 100005 
const double inf = 1e20;
struct Point{
    double x;
    double y;
};
Point p[MAX];
int ans[MAX];
double dis(Point p1,Point p2)
{
    return sqrt((p2.y-p1.y)*(p2.y-p1.y)+(p2.x-p1.x)*(p2.x-p1.x));
}
bool cmpy(const int & a,int& b)
{
     return p[a].y < p[b].y;
}
bool compxy(const Point& p1,Point& p2)
{
    if(p1.x!=p2.x)
        return p1.x<p2.x;
    return p1.y<p2.y;
}

double min(double a,double b)
{
    return a<b?a:b;
}
double divide(int left,int right)
{
    double d=inf;
    /*这里指只有一个点,那么最近点对的话距离自然就是inf了*/
    if(left==right)
        return d;
    //这里是判断是否为只有两个点,如果只有两个点的话那么直接求解。
    if(left+1==right)
        return dis(p[left],p[right]);
    //右移除2,对区域进行合理的划分,使得左右两边保持大致相等个数点
    int mid=(left+right)>>1; 
    double d1=devide(left,mid);
    double d2=devide(mid+1,right);
    d=min(d1,d2);
    int i,j,k=0;
    //通过横坐标确定[X-d,X+d]区域
    for(i=left;i<=right;i++)
    {
        if(fabs(p[mid].x-p[i].x)<=d)
           ans[k++]=i;
    }
    //通过排序,确定这写点按照纵坐标升序
    std::sort(ans, ans + k, cmpy);//线性扫描
    for(i=0;i<k-1;i++)
    {
        for(j=i+1;j<k && p[ans[j]].y-p[ans[i]].y<d;j++)
        {
            double distance=dis(p[ans[i]],p[ans[j]]);
            if(distance <d)
                d=distance;
        }
    }
    return d;
}
int main()
{
  int  i,j,N;
  while(scanf_s("%d",&N) && N!=0)
  {
     for(i=0;i<N;i++)
         scanf_s("%lf%lf",&p[i].x,&p[i].y);
     std::sort(p,p+N,compxy);//这里按照横坐标大小预排序,利用横坐标求中位线
     printf("%.2lf\n",divide(0,N-1)/2);
  }
  return 0;
}

其实,分治法的理解确实比较难,我在看了算法导论上面讲解之后也是一头雾水。所以后面就百度最近点对的分治算法。看了好多博客,最后终于明白了。所以这里真的非常感谢那些在自己明白了算法之后还乐于分享理解思路的博主们!所以,这里我也写一下自己对于算法的大概理解吧,或许在冥冥之中会给你带来一点点头绪。

Up_Junior1.


  1. *. ↩
1.3. 分治法—最近点对问题 1. 问题描述 给定平面S上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小 2. 求解过程 划分:将集合S分成两个大小基本相等的子集S1S_1S1​和S2S_2S2​ 求解子问题:递归地求解两个子问题 合并问题的解(三种情况) 组成S的最近点对的2个点都在S1S_1S1​中 组成S的最近点对的2个点都在S2S_2S2​中 组成S的最近点对的2个点分别在S1S_1S1​和S2S_2S2​中 3. 算法思路 预排序:把S中的点分别按x坐标值和y坐标值排序 如果S中包含的点少 阅读详情

相关推荐

最近点对问题(分治法)

问题描述 给定平面S上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小 蛮力法求解 点的存储: class Point{ //横坐标 int x; //纵坐标 int y; /** * 求解两个坐标之间的距离 * @return */ public static double distance(Point ri, Poi...

qq_41891805的博客 1万+

蛮力算法求解最近对

蛮力算法最近对 问题描述:一个包含n个点的集合中,找出距离最近的两个点。 问题分析:假设所考虑的点是以标准的笛卡尔坐标形式( x ,y )给出的,两个点pi = ( xi ,yi )和 pj =( xj,yj )之间的距离是标准的欧几里得距离 d( pi , pi )= 这里是引用 ...

zj的博客 3476

分治策略之最近点对问题

分治策略之最近点对问题问题:在平面给定N个点,求点对间最近距离。 分析:我们知道直线上找出2个最近的点,时间复杂度是O(NlogN),平面上比较所有的点对,直观上我们可以知道时间复杂度是O(N^2)。思考一下,当N非常大的时候,那不是得运算很久,有没有快速算法呢?我们采用分治策越,N个点我们不会做,我们进行Divide,分成两个子问题,N/2个点,依次进行下去。在子问题求出最小解,再回头进行Com

Rosun 1360

最近点对算法c语言,分而治之算法---距离最近的点对

给定n 个点(xi,yi)(1≤i≤n),要求找出其中距离最近的两个点。例14-7 假设在一片金属上钻n 个大小一样的洞,如果洞太近,金属可能会断。若知道任意两个洞的最小距离,可估计金属断裂的概率。这种最小距离问题实际上也就是距离最近的点对问题。通过检查所有的n(n- 1 ) / 2对点,并计算每一对点的距离,可以找出距离最近的一对点。这种方法所需要的时间为(n2 )。我们称这种方法为直接方法。图...

weixin_31766003的博客 2475

电工识图入门:从电气符号到控制逻辑的完整指南

电工图纸是电气工程领域的通用语言,无论是设备安装、线路检修还是系统设计,看不懂图纸就像航海没有海图。很多初学者面对复杂的电气符号和线路走向感到无从下手,实际上只要掌握正确的识图方法,就能从简单的照明电路逐步过渡到复杂的自动化控制系统。 本文将从最基础的电气符号和图纸类型讲起,通过实际图纸案例解析,带你建立完整的识图逻辑。你将学会如何区分主回路和控制回路,如何追踪电流路径,以及如何结合图纸进行故障排查。无论你是电工新手、设备维护人员还是相关专业学生,这套方法都能帮你快速提升图纸理解能力。 1. 电气图纸基础:

chengyixian7877的博客 337

实战演练:用wvp-GB28181-pro + ZLMediaKit搭建一个可用的国标视频监控测试环境(附设备模拟器对接)

本文详细介绍了如何使用wvp-GB28181-pro和ZLMediaKit在Ubuntu系统上搭建GB28181视频监控测试环境。从环境准备、组件解析到核心服务部署与设备模拟器对接,提供完整的实战指南,帮助开发者快速构建可验证的监控系统。

weixin_42692935的博客 580

C++实现蛮力法对最近点对问题的求解

本文给大家介绍的是蛮力法求解最近点对问题,最近点对问题就是给定一些点的坐标,求出其中距离最短的一对点的坐标及距离。本文可作为大学生实验报告;;包含 问题、原理、解释、完整代码、思路、总结、帮助各位大学生更好的完成日常实验报告。

xiaojiwazi的博客 959

信号处理领域的研究生看过来:手把手教你搞定ICASSP 2025论文投稿(附Latex模板与格式检查清单)

本文为信号处理领域研究生提供ICASSP 2025论文投稿的详细指南,涵盖Latex模板使用、格式检查清单及投稿流程。特别针对IEEE旗舰会议的严格要求和2025年可能出现的新变化,提供预判性建议和实战技巧,帮助作者高效完成论文投稿。

程涛 561

最近对问题(蛮力法)

问题描述:最近对问题是求解平面点集n个点中距离最近的两个点间的问题。为简单起见,在二维坐标平面来考虑该问题。如果讨论的点以标准二维坐标形式给出,则有点Pi(Xi,Yi)和Pj(Xj,Yj),二者的两点间距离可以利用公式d(Pi,Pj)=√(Xj-Xi)*(Xj-Xi)+(Yj-Yi)*(Yj-Yi)。通过这个公式,可以计算平面上任意两点之间的距离。 因此,蛮力法求解思路就是对平面n个点两两组队,...

abc1498880402的博客 4394

格拉姆角场(GAF)实战:用Python实现时间序列图像化处理

本文深入解析了格拉姆角场(GAF)技术,这是一种将一维时间序列转化为二维图像特征的方法,以便利用卷积神经网络(CNN)等图像模型进行深度分析。文章通过Python实战代码,详细演示了GASF和GADF两种核心转换的实现过程,并探讨了其在时序数据分类任务中的应用,为故障预警、金融模式识别等场景提供了强大的图像驱动分析视角。

weixin_29079671的博客 273

【Unity 城市建模插件】POLY-Megapolis City Pack 提供超过数百种城市建筑、道路、车辆与城市家具模型,完美适用于构建现代化城市、模拟城市游戏、都市题材冒险类游戏和开放世界项目

POLY - Megapolis City Pack 是一套风格统一、内容丰富的低多边形城市建模资源包,专为 Unity 引擎设计。该资源包提供超过数百种城市建筑、道路、车辆与城市家具模型,完美适用于构建现代化城市、模拟城市游戏、都市题材冒险类游戏和开放世界项目。无论是快速原型开发还是正式发布项目,POLY 系列都能提供高效、风格统一的解决方案。

2403_88403568的博客 635

平面最近点对问题求解—基于Java语言

平面最近点对问题求解—基于Java语言 1. 问题描述: 本问题来自《编程之美2.11—寻找最近点对》,文中给出了两种解法:暴力解法,分治解法。其中,暴力解法很简单,求出所有点之间的距离并做比较,便可找到距离最小的点对;当然,这不是最优解,时间复杂度为O(n^2)。文中还介绍了分治法,不过,没有给出源代码,网上的解法也多是基于C写的,本文将基于Java用分治法解决这个问题。 2.分...

Jin_Kwok的博客 7363

199、影像技术 roadmap 规划:未来移动影像的技术趋势与芯片算力展望

本文探讨了未来移动影像技术的发展趋势与芯片算力规划。作者从实际案例出发,指出影像技术演进需平衡传感器、ISP、算力和功耗。文章分为三部分:1)传感器将从堆像素转向提升信息密度,重点关注双层晶体管结构、混合快门和多光谱技术;2)ISP架构将向可编程计算单元转型,强调神经网络加速、硬件化多帧融合和语义处理;3)芯片算力瓶颈在于数据搬运,需优化存算一体架构、专用DMA和统一内存。最后给出五点建议:避免盲目追高像素、重视持续功耗、平衡ISP灵活性、预留算力余量、加强传感器与ISP协同设计。作者强调,影像技术的突破在

sundong_81的博客 60

分治法求解平面最近点对问题

平面最近点对问题描述分治求解 问题描述 给出一个平面内的若干个点,问这些点两两之间的最近距离是多少 弱数据题目链接 暴力自不必说,两个forforfor挨个看,时间复杂度是O(n2)O(n^2)O(n2),可以通过数据较小的测试 分治求解 数据加强题目链接 这里我们可以回忆一下归并排序是怎么做的,如何达到O(nlogn)O(nlogn)O(nlogn)的时间复杂度,采用的即是分治思想,也就是把一组数据对半分成两部分,继续划分,直至最小,排序拼回原数组,再排序,再拼回,直至全部排序完成 那么借助这个想法

ComingLiu的博客 1595

工业级向量检索核心技术:IVF-PQ原理与全流程解析

在大规模高维向量检索场景中,IVF-PQ(倒排索引结合乘积量化)凭借“粗筛范围+细算距离”的双重加速策略,成为核心解决方案。本文将深入解析其原理与全流程,助力开发者掌握这一关键技术。

进一步有进一步的欢喜~ 1199

构建高效的LLM应用测试框架

《构建高效的LLM应用测试框架》 关键词:LLM,测试框架,应用测试,效率优化,测试原理 摘要:本文将深入探讨构建高效LLM应用测试框架的必要性、方法与步骤,旨在为开发者提供一套系统化、可操作的测试解决方案,从而提升LLM

AI天才研究院 1048

求解平面最近点对的问题

(好吧。。。第一篇blog,之前没有写的习惯,现在还是开始慢慢记录下来吧~) 所谓最近点对呢,就是平面上给你一堆点,然后求出这堆点中相距最小的距离。 假如数据量比较小的话,那肯定是枚举所有点对求出各自距离再比较更方便了。很明显,枚举的时间复杂度是O(n²)。 不过一般不会给你这样的问题,点的个数往往很多,那就必然不能用枚举了。 这里要使用一种O(nlog(n))的算...

weixin_30307921的博客 246

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

C语言求解一维平面最近点对问题(注释详细)

采用递归/分治法解决 #include<stdio.h> #include<math.h> int aa = 0;//定义aa和bb两个点用于存储一维直线上点的下标 int bb = 0; int dd = 100;//随意定义的数字 int A[100]; int distance(int a,int b) { //两点之间的距离 return abs(a-b); } void closedis(int low, int high) { if (low == hig

Java_coder_guan的博客 2032

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

平面最近点对问题

平面最近点对问题求解—基于Java语言   1. 问题描述: 本问题来自《编程之美2.11—寻找最近点对》,文中给出了两种解法:暴力解法,分治解法。其中,暴力解法很简单,求出所有点之...

weixin_46668960的博客 705

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

hud 1007 Quoit Design 求解平面最近点对的问题

Problem Description Have you ever played quoit in a playground? Quoit is a game in which flat rings are pitched at some toys, with all the toys encircled awarded. In the field of Cyberground, the pos

退役的铜牌狗 738

用分治法求解最近点对问题

一、求解最近点对问题 【问题描述】给定平面S上n个点,找其中的一对点,使得在n个点组成的所有点对中,该点对间的距离最小。 (1)蛮力法求解最近点对问题 double ClosestPoints(vector<Point> a,int leftindex,int rightindex) { int i,j; double d,mindist =INF; for (i=le...

wmy01234的博客 6882

分治:平面中的最近点对问题的python实现

77

Arshion的博客 5150

平面最近点对——杨子曰题目

平面最近点对——杨子曰题目

杨子曰:代码是神奇的 388

Codeforces 429D Tricky Function(平面最近点对)

题目链接Tricky Function $f(i, j) = (i - j)^{2} + (s[i] - s[j])^{2}$ 把$(i, s[i])$塞到平面直角坐标系里,于是转化成了平面最近点对问题。 #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(...

weixin_30640769的博客 175

【HDU 5721】Palace(平面最近点对)

【HDU 5721】Palace(平面最近点对) Palace Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 404    Accepted Submission(s): 104 Problem Desc

ACMer' 3134

平面最近点对的分治做法及其证明

2018.6.23 好久没写博客了,做了一道有趣的分治题,写个博客。 题目传送门: P1429 平面最近点对(加强版) 题意 题目描述 给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的 输入格式 第一行:n;2≤n≤200000 接下来n行:每行两个实数:x y (0≤x,y≤10^9),表示一个点的行坐标和列坐标,中间用一个空格...

总理同学的编程尝试 9016
上一篇: android下数据库操作
下一篇: 关于字符串的算法
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值