1. 程式人生 > >平面最近點對問題

平面最近點對問題

ctype 但是 sof 算法 ans 之間 stream ant logs

平面最近點對問題正如其名,給定平面上的$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 }

清帝之惑之雍正

平面最近點對問題