二维平面最近点-分治

题目描述
给出二维平面上的n个点,求其中最近的两个点的距离的一半。
输入包含多组数据,每组数据第一行为n,表示点的个数;接下来n行,每行一个点的坐标。
当n为0时表示输入结束,每组数据输出一行,为最近的两个点的距离的一半。
输入样例:
2
0 0
1 1
2
1 1
1 1
3
-1.5 0
0 0
0 1.5
0
输出样例:
0.71
0.00
0.75
题目解析:
采用分治的思想,把n个点按照x坐标进行排序,以坐标mid为界限分成左右两个部分,
 对左右两个部分分别求最近点对的距离,然后进行合并。对于两个部分求得的最近距离d,
 合并过程中应当检查宽为2d的带状区间是否有两个点分属于两个集合而且距离小于d,最多
 可能有n个点,合并时间最坏情况下是O(n^2).但是,左边和右边中的点具有以下稀疏的性质,
 对于左边中的任意一点,右边的点必定落在一个d*2d的矩形中,且最多只需检查6个点(
 鸽巢原理),这样,先将带状区间的点按照y坐标进行排序,然后线性扫描,这样合并的时
 间复杂度为O(nlogn)。

代码:

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cmath>
using namespace std;
double MAX = 1e9;
int a,b;
struct Node{
    double x,y;
    int key;
};
Node ar[1000005],br[1000005];
bool cmpx(Node a,Node b){
    return a.x<b.x;
}
bool cmpy(Node a,Node b){
    return a.y<b.y;
}
double dis(Node a,Node b){
    return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));
}
double min(double a,double b){
    return a<b?a:b;
}
double cal(int s,int e){
    if(s==e)
        return MAX;
    int mid;
    mid = (s+e)/2;
    double d;
    d = min(cal(s,mid),cal(mid+1,e));
    int cnt = 0;
    for(int i=mid;i>=s&&ar[mid].x-ar[i].x<d;i--){
        br[cnt++] =  ar[i];
    }
    for(int i=mid+1;i<=e&&ar[i].x-ar[mid].x<d;i++){
        br[cnt++] = ar[i];
    }
    sort(br,br+cnt,cmpy);
    for(int i=0;i<cnt;i++){
        for(int j=i+1;j<cnt;j++){
            if(d>dis(br[i],br[j]))
                d = dis(br[i],br[j]);
        }
    }
    return d;
}

int main(){
    int n;
    while(cin>>n&&n){
        for(int i=1;i<=n;i++){
            scanf("%lf %lf",&ar[i].x,&ar[i].y);
            ar[i].key = i;
        }
        sort(ar+1,ar+n+1,cmpx);
        double d = cal(1,n);
        printf("%.2lf\n",d/2.0);
    }
    return 0;
}

思路:

采用是分治思想,按x轴分成两半,然后分别求两点之间最小距离min,不过要注意:两边可能分别存在一点,且距离最小,所以我们要把把单独把这一区间的最小值求出来,进行比较,才能确定整个二维空间两点之间的最小距离,由于这个区间中的点比较少,所以我们用两个for循环是不会超时的。

原文地址:https://www.cnblogs.com/lusiqi/p/11576044.html

时间: 2024-10-03 22:45:21

二维平面最近点-分治的相关文章

基于分治的二维平面最近点对算法实现

摘要: 网上有很多关于分治方法求最近点对的讨论,但是没有完整的可运行代码,本文主要对于该问题介绍一完整的可运行代码, 供有兴趣者参考. 正文: 作为对比,我们也同时实现了最近点对的枚举解法,具体的主函数如下: #include<stdio.h> #include<stdlib.h> #include "node.h" void initList(node* p) { p[0].x= 2.0; p[0].y= 1.0; p[1].x= 1.0; p[1].y= 2

HDU 1589 Stars Couple(计算几何求二维平面的最近点对和最远点对)

Time Limit: 1000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 930    Accepted Submission(s): 200 Problem Description Can you believe it? After Gardon had solved the problem, Angel accepted him! They were sitt

数字之魅:寻找二维平面上的最近的点对

在二维平面上的n个点中,如何快速的找出最近的一对点,就是最近点对问题. 初看这个题,可能感觉有点儿复杂. 方案一:蛮力法.数组中总共包含N个数,所以我们可以把平面内所有的点按X轴排序,然后依次算出后一个坐标与前面所有左边的距离,然后用Min和position来记录最近的距离和两个坐标.该方案和在一维空间求两个最近点的距离有点儿类似,其时间复杂度为:O(N*N). 方案二:在一维空间里,我们知道如果数组有序,我们可以很快找出最近的两个点.我们可以用O(N*logN)的时间复杂度来对数据进行排序[快

二维平面曼哈顿距离最小生成树模版

#include <stdio.h> #include <iostream> #include <algorithm> #include <sstream> #include <stdlib.h> #include <string.h> #include <limits.h> #include <vector> #include <string> #include <time.h> #i

9.7数学与概率(三)——在二维平面上,有两个正方形,请找出一条直线,能够将这两个正方形对半分

/** * 功能:在二维平面上,有两个正方形,请找出一条直线,能够将这两个正方形对半分. * 假定正方形的上下两条边与x轴平行. */ /** * 考虑: * 线的准确含义,可能性有: * 1)由斜率和y轴截距确定: * 2)由这条边上的任意两点确定: * 3)线段,以正方形的边作为起点和终点. * * 假设:这条线的端点应该落在正方形的边上. * 思路:要将两个正方形对半分,这条线必须连接两个正方形的中心点. */ public class Square { //正方形的四条边 int lef

POJ 3241 Object Clustering 二维平面曼哈顿距离最小生成树

题目链接:点击打开链接 题意: 给定二维平面上的n个点坐标,常数k 下面n行给出坐标 求一个最小生成树,问第k大的边是多少. 任意两个点间建一条边的花费是其曼哈顿距离. 思路:转自:点击打开链接 一.曼哈顿距离最小生成树 曼哈顿距离最小生成树问题可以简述如下: 给定二维平面上的N个点,在两点之间连边的代价为其曼哈顿距离,求使所有点连通的最小代价. 朴素的算法可以用O(N2)的Prim,或者处理出所有边做Kruskal,但在这里总边数有O(N2)条,所以Kruskal的复杂度变成了O(N2logN

9.7数学与概率(四)——在二维平面上,有一些点,请找出经过点数最多的那条线

/** * 功能:在二维平面上,有一些点,请找出经过点数最多的那条线. /** * 思路:在任意两点之间画一条无线长的直线,用散列表追踪那条直线出现的次数最多.时间复杂度O(N*N) * 注意: * 1)用斜率和y轴截距来确定是否是同一条直线. * 2)浮点数不一定能用二进制数准确表示,因此检查两个浮点数的差值是否在某个极小值(epsilon)内. * 3)对于散列表而言,斜率相等,未必散列值相同.因此,将斜率减去一个极小值,并以得到的结果flooredSlope作为散列键. * 4)取得所有可

给定二维平面整数点集输出“最大点集”算法(今日头条面试题)

引子 最近自己的独立游戏上线了,算是了却了一桩心愿.接下来还是想找一份工作继续干,创业的事有缘再说. 找工作之前,总是要浏览一些实战题目,热热身嘛.通过搜索引擎,搜到了今日头条的一道面试题. 题目 P为给定的二维平面整数点集.定义 P 中某点x,如果x满足 P 中任意点都不在 x 的右上方区域内(横纵坐标都大于x),则称其为"最大的".求出所有"最大的"点的集合.(所有点的横坐标和纵坐标都不重复, 坐标轴范围在[0, 1e9) 内) 如下图:实心点为满足条件的点的集

编写一个表示二维平面上的点的类MyPoint,满足以下条件: 1、定义private的成员变量x和y,表示点的x和y坐标,类型为double

编写一个表示二维平面上的点的类MyPoint,满足以下条件:1.定义private的成员变量x和y,表示点的x和y坐标,类型为double2.定义两个MyPoint的构造方法,一个构造方法不带参数,而且x和y的初始值为0,另一个构造方法有两个参数,参数名为x和y,类型为double,用这两个参数分别作为初始x和y坐标3.定义一个getD方法,有一个类型为MyPoint的对象参数,功能为返回当前对象和参数对象这两个坐标点的距离,返回值为double类型4.编写测试的main方法,调用getD计算两