平面临近点对
平面最近临近点对
问题描述:给定平面上的n个点(二维平面),求出距离最近的两个点。
例题 洛谷1257

算法描述:
分治:以中间点为划分线,分别求出左右两边的最近点对,然后求出左右两边的最近点对的最小值,然后求出中间两边的最近点对,最后取三者的最小值。
算法流程:
- 将所有点按照x坐标第一关键字,y为第二关键字排序
- 递归求出左右两边的最近点对,记为d1,d2,取最小值d=min(d1,d2),记为中间点为mid,找到区间中所有x坐标距离中间点小于d的点,记为b数组,b数组按照y坐标排序,遍历b数组,对于每个点,找到b数组中y坐标在y-d,y+d之间的点,更新最小距离d
- 对分割解释:一个区间的最近临近点对情况分为三种:在左侧区间,在右侧区间,区间两侧各有各有一个点,现在已经到得出左右两边的最近点对距离,接下来该分析最后一种情况。
- 对于最后一种情况首先要两侧的点横坐标距离小于d,然后要求出两侧的点中y坐标距离最小的两个点,这样才能保证得到区间两侧两个距离最小的点。
代码实现:
// Problem: 平面上的最接近点对
// Contest: Virtual Judge - %E6%B4%9B%E8%B0%B7
// URL: https://vjudge.net/problem/%E6%B4%9B%E8%B0%B7-P1257
// Memory Limit: 128 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#include<stack>
#include<vector>
#include<map>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long LL;
typedef pair<double,double> PDD;
const int N=2e5+10;
PDD a[N],b[N];
int n;
bool cmp(PDD a,PDD b){
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
bool cmpy(PDD a,PDD b){
return a.y<b.y;
}
double getd(PDD a,PDD b){
return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
double solve(int l,int r){
if(l==r) return 1e18;//如果只有一个点那么距离最大
if(l+1==r) return getd(a[l],a[r]);//相邻就直接返回两点距离
int mid=(l+r)>>1;
double d=min(solve(l,mid),solve(mid+1,r));//递归求左右两侧最近点
int k=0;
for(int i=l;i<=r;i++){//横坐标查找
if(fabs(a[i].x-a[mid].x)<d) b[k++]=a[i];
}
sort(b,b+k,cmpy);//纵坐标排序
for(int i=0;i<k;i++){
for(int j=i+1;j<k;j++){
if(fabs(b[j].y-b[i].y)>d) break;
d=min(d,getd(b[i],b[j]));//更新最近点距离
}
}
return d;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lf%lf",&a[i].x,&a[i].y);
}
sort(a,a+n,cmp);
printf("%.4f",solve(0,n-1));
return 0;
}

浙公网安备 33010602011771号