平面最近点对问题

平面最近点对问题正如其名,给定平面上的$n$个点,找出其中的一对点,使得这对点的距离在所有点对中最小。

 

首先显而易见地我们可以得到这个问题的$O(n^2)$算法,枚举所有点对即可。但是很显然我们可以注意到,这里面有很多点对显然不是最优的,那么我们可以想到一种剪枝方法,就是将只对x坐标差值小于当前已知最小值的点对进行判断(否则必然不是最优解),从而减少判断量。

 

我们考虑使用分治来实现这种剪枝,先将平面上的点分为两部分,分治求出两部分内部的最近点对距离。之后我们要做的就是枚举两个集合之间的点对,并与两部分内部的最近点对距离比较来得到最近点对距离。这里我们是不需要枚举所有点对的,因为我们已经得到了一个两部分各自内部最小的点对距离,因而我们可以结合上面的根据$x$坐标的剪枝方法,只枚举分别属于两部分的$x$坐标差小于已知最小距离的点对。

 

这样做的复杂度近似于$O(n\log^2n)$,至于怎么得到的……我也不知道。_(:зゝ∠)_

 

例题:

1. Vijos 1012 清帝之惑之雍正

链接:https://vijos.org/p/1011

2. 平面最近点对(加强版)

链接:https://www.luogu.org/problem/show?pid=1429

 

另外附上模板:

注意,本模板保留六位小数,不能直接用于提交上面的例题,若要提交请修改输出精度

 1 #include <iostream>
 2 #include <cstdlib>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <string>
 6 #include <sstream>
 7 #include <cctype>
 8 #include <cmath>
 9 #include <algorithm>
10 #define THE_BEST_PONY "Rainbow Dash"
11 
12 using namespace std;
13 const int maxn=220000,INF=~0u>>1;
14 
15 struct Point{
16     double x,y;
17     bool operator < (const Point &a) const {
18         if(x<a.x) return true;
19         if(x>a.x) return false;
20         return y<a.y;
21     }
22 }p[maxn];
23 
24 int n;
25 double ans;
26 
27 double DisP(int a,int b){
28     return sqrt((p[a].x-p[b].x)*(p[a].x-p[b].x)+(p[a].y-p[b].y)*(p[a].y-p[b].y)); 
29 }
30 
31 double GetAns(int l,int r){
32     int mid=(l+r)>>1;
33     if(l==r) return INF;
34     if(l==r-1) return DisP(l,r);
35     double len=min(GetAns(l,mid),GetAns(mid+1,r));
36     for(int i=mid;i>=l;i--){
37         if(p[i].x+len<p[mid].x) break;
38         for(int j=mid+1;j<=r;j++){
39             if(p[mid].x+len<p[j].x) break;
40             len=min(len,DisP(i,j));
41         }
42     }
43     return len;
44 }
45 
46 int main(){
47     scanf("%d",&n);
48     for(int i=0;i<n;i++)
49         scanf("%lf%lf",&p[i].x,&p[i].y);
50     sort(p,p+n);
51     ans=GetAns(0,n-1);
52     printf("%.6lf",ans);
53     return 0;
54 }
posted @ 2017-10-05 17:20  VKorpela  阅读(143)  评论(0编辑  收藏  举报
知识共享许可协议
爱与包容记心中 · 友谊魔法永流传
加密文章的密码是最棒的小马名字(没有空格)