阅读了一下平面最近点对的姿势,直接找了一道裸题来做。看完姿势的时候,我一直想不通合并时要怎么实现只考察最近6个点。。其实看了一下其他人的代码,好像都没有写只考察6个点。另外,每次合并,都要进行一次排序,那么它的真正复杂度是不是nlognlogn呢。。不管怎么样,比暴力快了许多。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <stdlib.h>
#include <math.h>
#include <stack>
using namespace std;
const int mod=1e9+7;
#define type double
#define Vector Point
const double PI = 3.14159265358979323;
//二维点/二维向量
struct Point{
type x,y;
Point(){
}
Point(type x,type y):x(x),y(y){
}
Point operator-(Point other){
return Point(x-other.x,y-other.y);
}
};
//向量长度
double Length(Vector a){
return sqrt(a.x*a.x+a.y*a.y+0.0);
}
Point pts[100010];
bool byx(const Point& a,const Point& b){
return a.x<b.x;
}
bool byy(const Point& a,const Point& b){
return a.y<b.y;
}
Point tmp[100010];
//最近点对
type Nearest(Point* pts,int l,int r){
if(r-l==2){
return Length(pts[l+1]-pts[l]);
}
if(r-l==3){
double re=min(Length(pts[l+1]-pts[l]),Length(pts[l+2]-pts[l]));
re=min(re,Length(pts[l+2]-pts[l+1]));
return re;
}
int mid = (l+r)>>1;
type Minl=Nearest(pts,l,mid);
type Minr=Nearest(pts,mid,r);
type re = min(Minl,Minr);
int cnt=0;
int pos;
//tmp暂存分割线附近的点
pos=mid-1;
while(1){
if(pos<l)break;
if(pts[pos].x>pts[mid].x-re){
tmp[cnt++]=pts[pos];
pos--;
}else{
break;
}
}
pos=mid;
while(1){
if(pos>=r)break;
if(pts[pos].x<pts[mid].x+re){
tmp[cnt++]=pts[pos];
pos++;
}else{
break;
}
}
//感觉有点耍流氓,能不能不排序
sort(tmp,tmp+cnt,byy); //通过y排序
for(int i=0;i<cnt;i++){
for(int j=i+1;j<cnt;j++){
if(tmp[j].y-tmp[i].y>re)break;
re=min(re,Length(tmp[j]-tmp[i]));
}
}
return re;
}
int main(){
int n;
while(cin>>n){
if(n==0)break;
for(int i=0;i<n;i++){
scanf("%lf%lf",&pts[i].x,&pts[i].y);
}
sort(pts,pts+n,byx);
double ans = Nearest(pts,0,n);
printf("%.2f\n",ans/2);
}
return 0;
}
本文详细介绍了如何通过裸题实践来优化查找平面内两点间距离最小值的问题,采用分治策略并限制搜索范围至最近6个点,显著提升算法效率。代码示例中包括了点的定义、距离计算、分治搜索及排序等关键步骤,展示了从暴力解法到优化算法的转变过程。
357

被折叠的 条评论
为什么被折叠?



