平面最近点对问题求解

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

OpenFOAM-多孔介质模型(porous media)

文章目录一、多孔介质(porous media)二、使用步骤1.达西定律2.Darcy-Forchheimer3.OpenFOAM fvOptions4.paraview动画每帧显示时间(Annotate Time)5.参考内容总结 一、多孔介质(porous media) 在流体力学中,流体流经多孔介质是指流体流经多孔介质时的行为方式,如海绵或木材,或使用沙子或其他多孔材料过滤水。 我们将展示如何设置多孔层,并使用OpenFOAM模拟流体通过该介质。 二、使用步骤 1.达西定律 达西定律最初是由达西通.

zq93538196的博客 9938

OpenMV识别颜色源码

【代码】OpenMV识别颜色源码。

dxt258013的博客 403

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

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

xiaojiwazi的博客 959

高德地图-获取定位-失败原因-浏览器定位异常场景

提示:也能实现,但是需要https协议,而且请求时间很长,要么你用梯子,还是不太合适.

shi15926lei的博客 4206

最近对问题(蛮力法)

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

abc1498880402的博客 4394

MATLAB离线附加功能包下载与安装教程

本文介绍如何下载与安装MATLAB离线附加功能包,便于大家更加高效的使用MATLAB。

加斯顿工程师的博客 1万+

工业缺陷标注要人命?我从零搭了一套自动标注系统,标注效率直接提升10倍

你是不是也深陷工业缺陷标注的无尽内耗?这不是个例,工业视觉项目落地,80%的时间和成本,都耗在了数据标注环节。普通的图像标注(猫狗分类、人脸识别),标注门槛低、规则简单、一致性要求宽松;而工业缺陷标注,是CV领域公认的地狱级难度:缺陷尺寸小到几像素、种类繁杂且非标、行业专业性极强、标注精度要求到像素级、正负样本极度不均衡,人工标注不仅效率低、成本高,更直接决定了模型的最终上限。我在工业视觉行业摸爬滚打了6年,踩遍了人工标注的所有坑,最终从零搭建了一套工业缺陷专用的闭环自动标注系统,把原来一张图30分钟的标注

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 202

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

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

Jin_Kwok的博客 7363

Oracle EBS的帐套由“4C”构成,而华为MetaERP将其发展为“6C”

华为MetaERP从OracleEBS的"4C"架构升级为"6C",实现核算理念革新。核心突破在于将会计科目、核算维度和核算单元解耦,形成"科目表+维度库"的灵活架构。新架构优势显著:1)科目回归会计本质,管理维度独立扩展;2)支持无限维度的精细化核算;3)实现数据权限隔离和内部交易自动化;4)采用元数据驱动设计,为AI应用奠定基础。这一平台化架构解决了大型企业在全球化、多元化发展中的核算难题,相比传统架构具有更强的灵活性和扩展性。

金牌架构师 204

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

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

ComingLiu的博客 1595

AIGC算法工程师-面试八股文-2025年版本-算法八股文/工程八股文/开放式问题

​两年前整理了《AIGC算法工程师 面试八股文》,全网一共有100w读者看过,收到了很多小伙伴的催更。Diffusion的技术发展非常快,博主特意整理了最近两年最新的八股文,内容非常全面,涵盖算法八股文/工程八股文/开放式问题三个大类,希望能为求职的读者们带来帮助。

沉迷单车的追风少年 4186

【Qt开发教程】网络代理QNetworkProxy类详解及实战应用

QNetworkProxy 提供了一种灵活而强大的方式来配置和管理网络代理,通过设置代理类型、主机、端口和认证信息,可以使应用程序的所有网络请求通过代理服务器进行。结合 QNetworkProxyFactory 可以实现动态代理选择和自动配置,提高应用的网络通信能力和安全性。在实际应用中,通过合理设置代理、处理代理认证和错误情况,可以确保应用程序在复杂的网络环境中稳定运行,为用户提供可靠的网络访问体验。

科技改变人类,技术成就未来 1542

求解平面最近点对的问题

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

weixin_30307921的博客 246

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

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

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

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

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

平面最近点对问题

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

weixin_46668960的博客 705

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

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

余额充值