1. 程式人生 > >Quoit Design (HDU 1007)平面的最近點對

Quoit Design (HDU 1007)平面的最近點對

題目大意:
給定平面上的 n 個點,求距離最近的兩個點的距離的一半。 n <= 10^5.

 

 暈乎乎的度過了一上午。。。

總之來學習下分治吧233

分治就是把大問題拆成小問題,然後根據對小問題處理出的結果合併成大問題的答案

比如說這道題,如果我們按照X座標把所有的點分成兩組:

 

(木哈哈請叫我盜圖狂魔○( ^皿^)っHiahiahia…

像上面我們把點分成了集合S1,S2

點對對應的被劃分成3種:S1內,S2內,跨S1.S2

那假若我們分別處理出了S1,S2內的答案,再取個min叫做d

那麼跨過分界線的點對就不能超過d,這是一個很有用的條件!不信?我們來看看

我們管分界線的X座標叫x0

首先要知道,所有距離x0超過d的點都不用考慮

其次,這些點之間y的相對距離超過d的也不用考慮

這就把對一個點而言需要考慮的另一個點們限制在了一個小矩形裡

再加上d是我們左右分治出來的答案

結論就是對於一個點我們最多隻需要考慮6個點就可以了

你可以自己畫畫?這六個點都分佈在矩形的頂點上

而具體實現其實就簡單暴力了

具體就看碼吧~

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using
namespace std; 5 int n,cnt; 6 struct point{ 7 double x,y; 8 }p[100005]; 9 int mk[100005]; 10 bool cmpx(point A,point B){return A.x<B.x;} 11 bool cmpy(int A,int B){return p[A].y<p[B].y;} 12 double dis(int x,int y){return sqrt((p[x].x-p[y].x)*(p[x].x-p[y].x)+(p[x].y-p[y].y)*(p[x].y-p[y].y));} 13
double solve(int l,int r){ 14 if(l==r)return 1e18; 15 if(l+1==r)return dis(l,r); 16 int mid=(l+r)>>1; 17 double x0=(p[mid].x+p[mid+1].x)/2.0; 18 double d=min(solve(l,mid),solve(mid+1,r)); 19 cnt=0; 20 for(int i=l;i<=r;i++) 21 if(p[i].x-x0<=d&&p[i].x-x0>=-d) 22 mk[++cnt]=i; 23 sort(mk+1,mk+1+cnt,cmpy); 24 for(int i=1;i<=cnt;i++) 25 for(int j=i-1;j>=1;j--) 26 if(p[mk[i]].y-p[mk[j]].y>d)break; 27 else d=min(d,dis(mk[i],mk[j])); 28 return d; 29 } 30 int main(){ 31 scanf("%d",&n); 32 for(int i=1;i<=n;i++)scanf("%lf%lf",&p[i].x,&p[i].y); 33 sort(p+1,p+1+n,cmpx); 34 printf("%.4lf",solve(1,n)); 35 return 0; 36 }
View Code