平面最近点对,即平面中距离最近的两点


分治算法:

int SOLVE(int left,int right)//求解点集中区间[left,right]中的最近点对

{

double ans; //answer

0)    调用前的预处理:对所有点排序,以x为第一关键词y为第二关键字 , 从小到大;

1)    将所有点按x坐标分成左右两部分;

/*      分析当前集合[left,right]中的最近点对,有两种可能:

1. 当前集合中的最近点对,点对的两点同属于集合[left,mid]同属于集合[mid,right]

则ans = min(集合1中所有点的最近距离, 集合2中所有点的最近距离)

2. 当前集合最近点对中的两点分属于不同集合:[left,mid][mid,right]

则需要对两个集合进行合并,找出是否存在p∈[left,mid],q∈[mid,right],使得distance(p,q)小于当前ans(即步骤1中求得的ans);

*/

2)    Mid = (left+right)/2;

ans = min( SOLVE(left,mid), SOLVE(mid,right) );

即:递归求解左右两部分中的最近距离,并取最小值;

//此步骤实现上文分析中的第一种情况

/*

再次进行分析

我们将集合[left,right]用x = mid这条直线分割成两部分

则如果画出直线l1:x=mid-ans 和 l2:x=mid+ans,显然如果有p∈[left,mid], q∈[mid,right]且distance(p,q) < ans则p,q一定在直线l1和直线l2之间,否则distance(p,q)必定大于ans。

于是扫描出在l1和l2之间的点

*/

3)    建立缓存数组temp[];

for i = left TO right

{

如果 abs(Point[i].x - Point[mid].x) <= ans

则向temp中加入点Point[i];

}

/*

对于temp中的点,枚举求所有点中距离最近两点的距离,然后与ans比较即可。

枚举的时候不必两两枚举。观察下图中的点p

 
         不难发现,若有q∈[mid,mid+ans]使得distance(p,q) <
ans,则q点的位置一定在图中画出的一个2ans×ansd的矩形中。可以证明点集[mid,mid+ans]中的、矩形外的点与p点的距离一定大于
ans。
           于是我们可以对temp以y为唯一关键字从小到大排序,进行枚举, 更新ans,然后在枚举时判断:一旦枚举到的点与p点y值之差大于ans,停止枚举。最后就能得到该区间的最近点对。

*/

4)    sort(temp);

for i = 0 TO k-1

{

for j = i+1 TO k-1

如果 temp[j].y - temp[i].y >= ans  break;

ans = min( ans, distance(temp[i], temp[j]) );

}

5)    return ans;

}

算法的时间复杂度

        由鸽巢原理,代码中第四步的枚举实际上最多只会枚举6个点,效率极高(一种蒟蒻的证明请看下方的评论)

本算法时间复杂度为O(n log n)

代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h> #define MIN( x , y ) ( (x) < (y) ? (x):(y) ) struct _Point
{
long long x;
long long y;
}Points[] , Tmp[]; int cmpxy ( const void *pa , const void *pb )
{
struct _Point *a = (struct _Point *)pa;
struct _Point *b = (struct _Point *)pb;
if ( a->x == b->x )
return a->y > b->y ? :-;
else
return a->x > b->x ? :-;
} int cmpy ( const void *pa , const void *pb )
{
struct _Point *a = (struct _Point *)pa;
struct _Point *b = (struct _Point *)pb; return a->y > b->y ? :-;
} double dis ( struct _Point a , struct _Point b )
{
return sqrt ( (double) ( (a.x - b.x ) * ( a.x - b.x ) + ( a.y - b.y ) * ( a.y - b.y ) ) );
} /*分治法求计算几何中平面点最近两点距离*/
double min_length ( struct _Point *p , long left , long right )
{
double min;
double d1,d2;
long mid;
long i , j ,k; if ( left == right )
return -; if ( left + == right )
return dis ( p[ left ] , p[ right ] ); mid = ( left + right ) >> ;
d1 = min_length ( p , left , mid );
d2 = min_length ( p , mid , right );
min = MIN( d1 , d2 ); for ( k = , i = left ; i <= right ; i++ ) { if ( fabs ( p[i].x - p[mid].x ) <= min )
Tmp[k++] = p[i];
} qsort ( Tmp , k , sizeof ( Tmp[] ) , cmpy );
for ( i = ; i < k - ; i++ ) { for ( j = i + ; j < k ; j++ ) { if ( fabs( Tmp[i].y - Tmp[j].y ) >= min )
break; min = MIN ( min , dis ( Tmp[i] , Tmp[j] ) );
}
} return min;
} int main ( int argc , char *argv[] )
{
long n;
long i; scanf("%ld" , &n ); for ( i = ; i < n ; i++ )
scanf ("%ld%ld" , &Points[i].x , &Points[i].y ); qsort ( Points , n , sizeof ( Points[] ) , cmpxy );
printf ("%.3f" , min_length ( Points , , n - ) );
return ;
}

部分转载:http://blog.csdn.net/lytning/article/details/25370169

计算几何 平面最近点对 nlogn分治算法 求平面中距离最近的两点的更多相关文章

  1. Vijos 1012 清帝之惑之雍正 平面最近点对(分治)

    背景 雍正帝胤祯,生于康熙十七年(1678)是康熙的第四子.康熙61年,45岁的胤祯继承帝位,在位13年,死于圆明园.庙号世宗. 胤祯是在康乾盛世前期--康熙末年社会出现停滞的形式下登上历史舞台的.复 ...

  2. Luogu P1429 平面最近点对 【分治】By cellur925

    题目传送门 题目大意:给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的.$n$<=100000. $Algorithm$ 最朴素的$n^2$枚举肯定 ...

  3. 分治算法求乘方a^b 取余p(divide and conquer)

    传统的计算方法为循环n个a相乘.时间复杂度为O(n). 如用分治算法,效率可提升至O(lgn). 结合recursive有 double pow(int a, int n){ ) ; ) return ...

  4. Luogu4423 BJWC2011 最小三角形 平面最近点对

    传送门 题意:给出$N$个点,求其中周长最小的三角形(共线的也计算在内).$N \leq 2 \times 10^5$ 这道题唤起了我对平面最近点对的依稀记忆 考虑平面最近点对的分治,将分界线两边的求 ...

  5. POJ 1986 Distance Queries (Tarjan算法求最近公共祖先)

    题目链接 Description Farmer John's cows refused to run in his marathon since he chose a path much too lo ...

  6. 平面最近点对(分治nlogn)

    平面最近点对,是指给出平面上的n个点,寻找点对间的最小距离 首先可以对按照x为第一关键字排序,然后每次按照x进行分治,左边求出一个最短距离d1,右边也求出一个最短距离d2,那么取d=min(d1, d ...

  7. Luogu 1429 平面最近点对 | 平面分治

    Luogu 1429 平面最近点对 题目描述 给定平面上n个点,找出其中的一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的 输入输出格式 输入格式: 第一行:n:2≤n≤200000 ...

  8. Luogu P1429 平面最近点对(加强版)(分治)

    P1429 平面最近点对(加强版) 题意 题目描述 给定平面上\(n\)个点,找出其中的一对点的距离,使得在这\(n\)个点的所有点对中,该距离为所有点对中最小的. 输入输出格式 输入格式: 第一行: ...

  9. P1429 平面最近点对(加强版)(分治)

    P1429 平面最近点对(加强版) 主要思路: 分治,将点按横坐标为第1关键字升序排列,纵坐标为第2关键字升序排列,进入左半边和右半边进行分治. 设d为左右半边的最小点对值.然后以mid这个点为中心, ...

随机推荐

  1. 统一者管理员指南(Unifier Administration Guide)中文

    统一者管理员指南 Unifier Administration Guide 2014年6月 发布 2014年11月翻译 10.0版本 10.0.1译 关于译者 翻译者QQ:77811970 Email ...

  2. 一个App的界面设计流程是怎么产生的

    作者:候佩雯链接:http://www.zhihu.com/question/27088793 完整的流程,分层次设计,自下而上去完成: 策略层,定义产品使命.价值.目标人群 愿景/功能层:定义核心场 ...

  3. 【jQuery基础学习】02 jQuery的DOM操作

    DOM操作分为3个方面: DOM Core    任何一种支持DOM Core的语言都可以使用它,比如getElementById就是DOM Core操作 HTML-DOM  只能用来处理web文档 ...

  4. java中使用 正则 抓取邮箱

    我们来抓取豆瓣网的邮箱吧!把这个页面的所有邮箱都抓取下来 如https://www.douban.com/group/topic/8845032/: 代码如下: package cn.zhangzon ...

  5. nginx跨域处理

    http://www.nginx.cn/nginx-download nginx.conf配置 if ($request_method = ‘OPTIONS’) {         add_heade ...

  6. 2004-输入一个百分制的成绩t,将其转换成对应的等级

    ,具体转换规则如下: 90~100为A; 80~89为B; 70~79为C; 60~69为D; 0~59为E; 如果输入数据不在0~100范围内,请输出一行:“Score is error!”. 这题 ...

  7. sqlserver允许远程连接的配置

    如果无法通过IP地址远程连接你服务器上的SQL Server服务器,可以参考下面的内容进行设置 在进行下述设置之前,应该确保你的网络已经安装设置完毕,服务器已经正常连接到网络中. 1.单击Window ...

  8. 常用 windows运行命令

    winver---------检查Windows版本 wmimgmt.msc----打开windows管理体系结构(WMI) wupdmgr--------windows更新程序 wscript--- ...

  9. SharePoint 2013 设置自定义布局页

    在SharePoint中,我们经常需要自定义登陆页面.错误页面.拒绝访问等:不知道大家如何操作,以前自己经常在原来页面改或者跳转,其实SharePoint为我们提供了PowerShell命令,来修改这 ...

  10. github 基础教程推荐

    github现在很火的样子 我在一篇博客上看到说“如果你不知道什么是github,那你就不能说你是个coder,如果你现在看到这篇博客,那么你已经是个coder了”. 我对github一直很好奇,可是 ...