算法(三)最小点对

求最小点对主要是分治的思想,divide and qunquer

先将所有的点按照x(或y)排序,然后找中间轴,分别求轴两边的最小点对,以此递推。

然后找位于轴两侧的点中是否有点对距离更小

找到所有与中轴的距离小于当前最小距离的点,然后按照y(或x)排序,找这些点中是否有距离更小的点对。

一旦有点对的y坐标差大于最小距离,就可以break,以此减少时间复杂度。

附上代码:hdu 1007

#include<iostream>
#include<stdio.h>
#include<vector>
#include<algorithm>
#include<limits>
#include<math.h>


#define N 100000


using namespace std;


struct point{
double x;
double y;
};


point p[N + 10];
point po[N + 10];


double min(double a , double b){
return a < b? a:b; 
}
double dis(point a,point b){
return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
}
bool cmp(const point &a, const point &b){
if(a.y<b.y || a.y==b.y && a.x<b.x){
return true;
}
return false;
}
bool comp(const point &a, const point &b){
return a.x<b.x;
}
double closestDistance(int start, int end){
double minDis = numeric_limits<double>::max(); 
if(end - start <= 2){
if(end - start == 2){
minDis = min( min( dis(p[start],p[start+1]), dis(p[start],p[end]) ), dis(p[start+1],p[end]) );
}
if(end - start == 1){
minDis = dis(p[start],p[end]);
}
return minDis;
}

int mid = (start+end) / 2;
double left = closestDistance(start,mid);
double right = closestDistance(mid+1,end);
minDis = min(left,right);
// cout<<"left "<<left<<" right "<<right<<endl;
int num = 0; 
for(int i=start; i<=end; i++){
if((p[i].y-p[mid].y)*(p[i].y-p[mid].y) <= minDis){
po[num++] = p[i];
}

sort(po,po+num,comp);

for(int j=0; j<num; j++){
for(int k=j+1; k<num; k++){
if((po[j].x-po[k].x) * (po[j].x-po[k].x) >= minDis){
break;
}
minDis = min(minDis,dis(po[j],po[k]));
}
}
return minDis;
}
int main(){
int n;
while(scanf("%d",&n)!=EOF && n!=0){
for(int i = 0; i < n;i++){
scanf("%lf%lf",&p[i].x,&p[i].y);

}
sort(p,p+n,cmp);
double ans = closestDistance(0,n-1);
ans = sqrt(ans)/2;
printf("%.2lf\n",ans);
}
return 0;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值