平面最近点对问题求解

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

PostgreSQL隐式类型转换全解析:告别operator does not exist

强类型数据库是现代数据系统的基石,它在带来严谨性的同时,也常常让开发者在类型不匹配报错前束手无策。当一条SQL因bigint与text比较而抛出operator does not exist时,根源往往在于对数据库隐式转换规则的误解。PostgreSQL通过pg_cast系统表将转换划分为隐式、赋值与显式三个级别,并依据操作符解析逻辑决定是否自动提升类型。理解这些机制,不仅能快速定位JOIN、UNION、函数调用等场景下的类型错误,还能帮助开发者合理使用EXPLAIN VERBOSE、pg_typeof等工

weixin_29587015的博客 304

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

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

xiaojiwazi的博客 959

ChatGPT Web转API工具:原理、部署与集成实战

在AI应用开发中,API(应用程序编程接口)是实现系统间通信和数据交换的核心技术,它通过标准化的请求响应机制,将复杂功能封装为可编程的服务。其工作原理基于HTTP协议,通过定义清晰的端点、方法和数据格式,使不同平台的应用能够高效集成AI能力。这一技术价值在于极大降低了开发门槛,促进了自动化流程和智能功能的快速落地,广泛应用于智能客服、内容生成和创意辅助等场景。本文聚焦于如何通过浏览器自动化技术,将ChatGPT的Web界面能力转化为标准API服务,其中涉及Playwright无头浏览器操作和会话Cookie

weixin_42533910的博客 1767

最近对问题(蛮力法)

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

abc1498880402的博客 4394

极简JEPA世界模型实战:低门槛复现LeWorldModel,CPU可跑

这次我们来看一个能让普通开发者真正上手跑起来的“世界模型”项目。如果你对Yann LeCun提出的JEPA(联合嵌入预测架构)框架感兴趣,但又苦于Meta官方实现过于庞大复杂,那么这个GitHub上4k star的项目就是为你准备的。它用极简的PyTorch代码(核心文件仅160-278行)完整复刻了包括LeWorldModel在内的五个JEPA核心变体,最大的亮点是: 门槛极低,普通笔记本甚至CPU就能跑,显存占用友好,非常适合学习和原理验证。 这个项目名为 keon/jepa ,完全开源。它剥离了工业级

weixin_29031161的博客 421

基于STM32L4XX、HAL库的 L76KB-A58定位模块驱动程序设计

/ 确保字符串终止。// 缓冲区溢出,重置。// 重置缓冲区索引。支持GPS、GLONASS、Galileo、北斗和QZSS多系统定位。case 1: // UTC时间。// 配置GPS模块(可选)// 查找GGA语句。// 启动UART接收。// USART1初始化函数。内置LNA和SAW滤波器。

zhusl6688的博客 349

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

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

Jin_Kwok的博客 7363

14、方法论 - 自顶向下与自底向上的结合

本文探讨了如何将自顶向下的规范驱动方法与自底向上的组件构建方法相结合,以形成更加全面的编程理论。通过引入代数法则,简化逻辑关系、提高代码可读性并支持形式化验证,结合实际案例(如智能家居控制系统)展示了如何在设计和实现阶段确保系统的正确性和可靠性。文章还讨论了工具支持的重要性,并提出了未来发展的方向。

lstm7chronicler的博客 175

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

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

ComingLiu的博客 1595

利用SIMULINK搭建一个16QAM调制解调收发系统

1发送模块设计 根据前面介绍的理论知识,我们可以知道16QAM的基本结构,首先我来设计QAM发送段的SIMULINK仿真模块。 图1 16QAM的发送端模块 他的基本工作流程为:将信号通过两路升余弦滤波器,得到滤波以后的信号,滤波器的作用就是为了防止码间干扰。然后将滤波以后的信号和SIN,COS相乘得到调制信号,将调制 下面一一介绍每个模块的具体参数设置以及各个部分信号的波形图。 图2 产生随机数据的信号源 第一部分信号是产生一组随机的数字,作为信源,第二个模块将信号...

FPGA/MATLAB学习教程/源码/项目合作开发 4776

Unreal5从入门到精通之如何解决在VR项目在头显中卡顿的问题

以前我们使用Unity开发VR,Unity提供了非常便利的插件和工具来做VR。但是由于Unity的渲染效果不如Unreal,现在我们改用Unreal来做VR了,所有的VR相关的配置和操作都要重新学习。今天就来总结一下,我在开发VR过程中碰到的所有问题。好了,以上就是我目前做VR时碰到的一些问题,希望对你有所帮助。

TxNet 2482

求解平面最近点对的问题

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

weixin_30307921的博客 246

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

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

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

平面最近点对问题

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

weixin_46668960的博客 705

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

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、付费专栏及课程。

余额充值