您的位置:首页 > 其它

经典问题之最近点对问题

2016-06-12 12:18 190 查看
解决问题:在平面内有n个点,求两两之间的最短距离。

题解:

1.枚举点,打擂台。O(n^2)

2.分治。先按x坐标排序,以中位数画一条线,将平面分成两个部分,对两个左右部分分别处理,然后合并。

合并:设总区间d=min{左区间d,右区间d}划分左右之后,按照y的大小归并两个区间的点坐标,然后以d为上届,刷去一些点,对于剩下的点直接左右互相算距离,打擂台即可。效率经证明为O(nlog n).

参考程序:

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#define maxn 21000
#define INF 0x7f7f7f7f
using namespace std;
int n;
struct Pair{
int x,y;
bool operator < (const Pair& rhs) const {
return x<rhs.x;
}
}loc[maxn];
bool cmp_y(Pair a,Pair b){
return a.y<b.y;
}
double closeset_pair(Pair *a,int n){
if (n<=1)return INF;
int m=n/2;
double x=a[m].x;
double d=min(closeset_pair(a,m),closeset_pair(a+m,n-m));
inplace_merge(a,a+m,a+n,cmp_y);
vector<Pair> b;
for (int i=0;i<n;i++){
if (fabs(a[i].x-x)>=d)continue;
for (int j=0;j<b.size();j++){
double dx=a[i].x-b[b.size()-j-1].x;
double dy=a[i].y-b[b.size()-j-1].y;
if (dy>=d)break;
d=min(d,sqrt(dx*dx+dy*dy));
}
b.push_back(a[i]);
}
return d;
}
int main(){
scanf("%d",&n);
for (int i=0;i<n;i++)
scanf("%d%d",&loc[i].x,&loc[i].y);
sort(loc,loc+n);
printf("%f",closeset_pair(loc,n));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: