题目描述
有一天,小明得到了二维平面上的若干个点,他现在想知道这些点中距离最近的两个点之间的距离是多少?

输入
第一行输入一个整数T,共有T组测试数据(T<=30)。
每组输入数据第一行输入一个n,表示有n个点。第二行有n*2的数字,相邻两个数代表一个点的x,y坐标。
1<n<=100, -100000000=<x,y<=100000000

输出
输出有T行,每行包括一个整数,代表所有距离的最小值(因为小明不在意小数,所以结果向下取整)。

样例输入 Copy
2
2
0 0 1 1
2
0 0 100000000 100000000
样例输出 Copy
1
141421356

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const double INF = 1e20;
const int N = 100005;  struct Point
{  double x;  double y;
}point[N];
int n;
int tmpt[N];  bool cmpxy(const Point& a, const Point& b)
{  if(a.x != b.x)  return a.x < b.x;  return a.y < b.y;
}  bool cmpy(const int& a, const int& b)
{  return point[a].y < point[b].y;
}  double min(double a, double b)
{  return a < b ? a : b;
}  double dis(int i, int j)
{  return sqrt((point[i].x-point[j].x)*(point[i].x-point[j].x)  + (point[i].y-point[j].y)*(point[i].y-point[j].y));
}  double Closest_Pair(int left, int right)
{  double d = INF;  if(left==right)  return d;  if(left + 1 == right)  return dis(left, right);  int mid = (left+right)>>1;  double d1 = Closest_Pair(left,mid);  double d2 = Closest_Pair(mid+1,right);  d = min(d1,d2);  int i,j,k=0;  //分离出宽度为d的区间  for(i = left; i <= right; i++)  {  if(fabs(point[mid].x-point[i].x) <= d)  tmpt[k++] = i;  }  sort(tmpt,tmpt+k,cmpy);  //线性扫描  for(i = 0; i < k; i++)  {  for(j = i+1; j < k && point[tmpt[j]].y-point[tmpt[i]].y<d; j++)  {  double d3 = dis(tmpt[i],tmpt[j]);  if(d > d3)  d = d3;  }  }  return d;
}  int main()
{  int m;
scanf("%d",&m);while(m--)  {  scanf("%d",&n);  if(n==0)  break;  for(int i = 0; i < n; i++)  scanf("%lf %lf",&point[i].x,&point[i].y);  sort(point,point+n,cmpxy);  printf("%d\n",int(Closest_Pair(0,n-1)));  }  return 0;
}  

解析:用分治的方法解决。
算法:

0:把所有的点按照横坐标排序

1:用一条竖直的线L将所有的点分成两等份

2:递归算出左半部分的最近两点距离d1,右半部分的最近两点距离d2,取d=min(d1,d2)

3:算出“一个在左半部分,另一个在右半部分”这样的点对的最短距离d3。

4:结果=min(d1,d2,d3)

关键就是这第3步。貌似这需要n^2的时间,把左边每个点和右边每个点都对比一下。其实不然。秘密就在这里。 首先,两边的点,与分割线L的距离超过d的,都可以扔掉了。 其次,即使两个点P1,P2(不妨令P1在左边,P2在右边)与分割线L的距离(水平距离)都小于d,如果它们的纵坐标之差大于d,也没戏。 就是这两点使得搜索范围大大减小: 对于左半部分的,与L的距离在d之内的,每个P1来说:右半部分内,符合以上两个条件的点P2最多只有6个! 原因就是: d是两个半平面各自内,任意两点的最小距离,因此在同一个半平面内,任何两点距离都不可能超过d。 我们又要求P1和P2的水平距离不能超过d,垂直距离也不能超过d,在这个d2d的小方块内,最多只能放下6个距离不小于d的点。 因此,第3步总的比较距离的次数不超过n6。

第3步的具体做法是:

3.1 删除所有到L的距离大于d的点。 O(n)

3.2 把右半平面的点按照纵坐标y排序。 O(nlogn)

3.3 对于左半平面内的每个点P1,找出右半平面内纵坐标与P1的纵坐标的差在d以内的点P2,计算距离取最小值,算出d3。 O(n*6) = O(n) 因为3.2的排序需要O(nlogn), 所以整个算法的复杂度就是O(n((logn)^2))。

改进: 我们对3.2这个排序的O(nlogn)不太满意。 既然整个算法是递归的,我们可以利用第2步的子递归中已经排好序的序列,在第3.2部归并这两个子列,这样3.2的复杂度变成了O(n)。 这样,整个算法就是O(nlogn)的。

在二维平面上的n个点中,如何快速的找出最近的一对点,就是最近点对问题。

一种简单的想法是暴力枚举每两个点,记录最小距离,显然,时间复杂度为O(n^2)。在这里介绍一种时间复杂度为O(nlognlogn)的算法。其实,这里用到了分治的思想。将所给平面上n个点的集合S分成两个子集S1和S2,每个子集中约有n/2个点。然后在每个子集中递归地求最接近的点对。在这里,一个关键的问题是如何实现分治法中的合并步骤,即由S1和S2的最接近点对,如何求得原集合S中的最接近点对。如果这两个点分别在S1和S2中,问题就变得复杂了。为了使问题变得简单,首先考虑一维的情形。此时,S中的n个点退化为x轴上的n个实数x1,x2,...,xn。最接近点对即为这n个实数中相差最小的两个实数。显然可以先将点排好序,然后线性扫描就可以了。但我们为了便于推广到二维的情形,尝试用分治法解决这个问题。假设我们用m点将S分为S1和S2两个集合,这样一来,对于所有的p(S1中的点)和q(S2中的点),有p<q。递归地在S1和S2上找出其最接近点对{p1,p2}和{q1,q2},并设d = min{ |p1-p2| , |q1-q2| }由此易知,S中最接近点对或者是{p1,p2},或者是{q1,q2},或者是某个{q3,p3},如下图所示。如果最接近点对是{q3,p3},即|p3-q3|<d,则p3和q3两者与m的距离都不超过d,且在区间(m-d,d]和(d,m+d]各有且仅有一个点。这样,就可以在线性时间内实现合并。此时,一维情形下的最近点对时间复杂度为O(nlogn)。在二维情形下,类似的,利用分治法,但是难点在于如何实现线性的合并?由上图可见,形成的宽为2d的带状区间,最多可能有n个点,合并时间最坏情况下为n^2,。但是,P1和P2中的点具有以下稀疏的性质,对于P1中的任意一点,P2中的点必定落在一个d X 2d的矩形中,且最多只需检查六个点(鸽巢原理)。这样,先将带状区间的点按y坐标排序,然后线性扫描,这样合并的时间复杂度为O(nlogn),几乎为线性了。

参考链接1
参考链接2

二维平面最短距离(分治)相关推荐

  1. 二维树状数组 ----2021广东省赛 ----- K - Kera‘s line segment[区间转二维平面+树状数组维护前缀最小最大值]

    题目链接 题目大意: 就是一个一维的数轴上面有一堆线段用一个三元组(l,r,val)(l,r,val)(l,r,val)表示. 现在我们有两个操作: 就是往数轴上面添加线段 询问[L,R][L,R][ ...

  2. 二维平面内无人机的路径规划——势场法-改进

    通过这一算法可以实现二维平面内无人机的路径规划.在该平面内存在已知的障碍,势场法通过给终点添加引力,对障碍增加斥力,使得无人机能够顺利的避障并到达终点.通过对传统势场法的改进,避免了无人机容易陷入极值 ...

  3. 编程题:二维平面整数点集求最大值

    题目描述: P为给定的二维平面整数点集.定义 P 中某点x,如果x满足 P 中任意点都不在 x 的右上方区域内(横纵坐标都大于x),则称其为"最大的".求出所有"最大的& ...

  4. Fall with Trees 二维平面直角坐标系-凸包-推公式

    题意 : 二维平面直角坐标系中,给出根节点和左右子节点的坐标,按照规范画k层满二叉树并求凸包面积 思路 : 将每一层的梯形转化为三角形. 将pow换成qmi反而会inf,每一组样例中只需要一次所以可以 ...

  5. 轮廓线重建:二维平行轮廓线重建理论和方法

    1.前言 MarchingCube方法重建三维物体表面的过程是依据像素灰度值的比较来确定等值点,从而得到组成等值面的三角片.由于表征器官组织密度的灰度值是一个在空间分布上不连续的数据,所以仅靠一个灰度 ...

  6. ITK:使用均方执行二维平移配准

    ITK:使用均方执行二维平移配准 内容提要 输出结果 C++实现代码 内容提要 本示例说明了Insight中图像注册框架的用法.应该将其读为ITK注册.该示例应作为对解决图像配准问题时通常涉及的元素的 ...

  7. Java黑皮书课后题第10章:*10.15(几何:边框)边框是指包围一个二维平面上点集的最小矩形,编写一个方法,为二维平面上一系列点返回一个边框

    *10.15编写一个方法,为二维平面上一系列点返回一个边框 题目 程序 代码 Test15.java Test13_MyRectangle2D.java 运行结果 题目 点击这里跳转编程练习题10.1 ...

  8. 【飞控理论】【惯性导航基础】二维平面的旋转如何用代数表示?三维平面的旋转如何用代数表示?什么是四元数?四元数、欧拉角、方向余弦之间有什么关系?

    上一篇欧拉角 由于欧拉角在描述三维空间物体旋转问题时存在万向节死锁问题(详情戳这里),所以引入四元数概念. 目录 1.二维平面的旋转 2.三维平面的旋转(什么是四元数) 3.<捷联惯性导航> ...

  9. 关于线段树or 树状树状 在二维平面搞事情!Orz

    第一式:https://ac.nowcoder.com/acm/contest/143/I 题意: 有 n 个点,一个点集 S 是好的,当且仅当对于他的每个子集 T,存在一个右边无限长的矩形,使得这个 ...

最新文章

  1. java基础之——类的初始化顺序(转载)
  2. JAVA面试解析(有赞二面)
  3. 神盾局hive是什么_《神盾局特工》第七季再爆幕后照,这位角色复古装又美出新高度...
  4. k-means算法的理解与实现
  5. android 如何使用SAX解析XML
  6. tf.layers.dropout
  7. eclipse mysql生成实体类_Eclipse实现数据库反向生成实体类(pojo)-------(插件安装和实现步骤的说明)...
  8. leetcode557. 反转字符串中的单词 III
  9. 判断字符串中是否包含指定字符(JavaScript)
  10. Java每日问题汇总-02
  11. scp shell脚本无需密码输入
  12. fgo7.27服务器维护,【公告】更新游戏数据资料(7/27 实施)
  13. Llinux文件操作四剑客
  14. 关于css3的背景切割(background-clip)、背景原点(background-origin)的使用
  15. php批量导入txt文件,如何把一个文本文件中的十几万数据快速的导入到sql表中
  16. excel index 函数
  17. GenBank数据格式
  18. App小程序开发外包的费用大约是多少?
  19. 解决“error C1083: 无法打开包括文件: “HPSocket.h”: No such file or directory”
  20. Python基础阶段:体脂率计算练习

热门文章

  1. 南京大学计算机 曹云浩,【2015.青春曲园】第二十六届“迎校庆”校园十佳歌手大赛独家放送~...
  2. 艾司博讯:拼多多机器人客服在哪里
  3. 深入 Go 中各个高性能 JSON 解析库
  4. work english words
  5. 如何怎样在M1芯片Mac上安装PS?M1芯片安装Photoshop详细教学方法2021最新方法
  6. 用友系统服务器,用友财务系统需要什么云服务器
  7. 春分。谓之分。秋同义。
  8. 微信扫码登陆在chrome浏览器被拦截
  9. Qt实现Linux下的硬盘空间监测和文件清理
  10. python画哆啦a梦图片_80行代码!用Python做一个哆来A梦分身