分割統治 - 問題の最も近いポイントhdu1007

問題の説明

nは公共空間における点は、極小点対のユークリッド距離上のすべての点に対して決定されます。
上の最も近い点 

解決策1:もちろん、暴力的な和解は$ O(N ^ 2)$でした

 

解決策2:我々は$ O(nlognの*のLOGN)$も$ O(nlogn)$にアルゴリズムを最適化することができ、イデオロギー的分裂を使用し、征服します

のは、xがポイントのすべての並べ替えを座標従ってみましょう、そして各半分が、この二分法がよく、難易度がマージされ、操作を書かれたことは明らかです。すなわち、右及び集合B内の点を選択する点から左側のセットを選択します。 

暴力は左ポイントと右、または$ O(N ^ 2)$を列挙している場合。 

まず第一に、我々は最初のコレクションの左右への最短距離を見つけます。$ D =分(dist_ {左}、dist_ {右})$ 

 その後、ストリップのセットの周りに境界線を見つけます。図に示すように。

マージ

lはセットの周りに境界線です。 

私たちはちょうど横軸[半ばD、ミッド]、および左その上の範囲内のコレクションペアリング[ミッド、ミッド+ D]ポイント内部の右側に横軸の内側に設定列挙ことがわかりました。明らかに、より確実の別の点からからです。  

これは非常に私達の範囲の列挙は減少しますが、極端な場合には依然として非常に大きいです。 

 

 

1985 PreparataとShamos分裂における統治アルゴリズムが問題に与えられ、彼は左と彼の試合の右のセット上の任意の点のために最も解けるの6点の唯一最大になったことを指摘しました。

6

示す:pは左、右境界点Pが対にすることができ、より多くない6点、6点の唯一最大即ちδ×2δ間隔上のポイントである場合。  

 

私たちは、矛盾によって証明します。  

6point

我々は$ \ FRAC {2δ} {3} $点ごとこのマトリックス2δ×δので、我々は、2つのは、これがその後、存在する場合、それぞれの小行列は、一点のみとなるまでに知る6つの小さな長方形であります2点間の距離は、明らかに、遠い対角線最短距離でなければなりません。 

この対角距離で$ \ SQRT {\ FRAC {2δ} {3}の\ FRAC×{2δ} {3} + \ FRAC {δ} {2}の\ FRAC×{δ} {2} = \でありますFRAC {\ sqrtの{5}} {6}δの$

このとき、原稿は(D及びδは同じである)、D未満の右点で説明されており、明確に元に一致しません。 

このため、6点の唯一最大。(もちろん、実際には、それはあまりポイントを証明できます)  

所以我们每次合并,对于左边的点最多只有6个匹配的方案。 考虑匹配方案的时候,需要对y进行排序,那么时间复杂度就变成了$O(n*logn*logn)$。  

但是其实我们可以做的更好,我们可以在分治的过程中,顺便做一个关于y坐标的归并排序,这样就不用每次对y进行sort了,时间也可以优化到$O(nlogn)$

下面是我的代码,还是写了2个$logn$的做法。 

 1 #include<bits/stdc++.h>
 2 using namespace std; 
 3 int const N=100000+10;   
 4 struct node{
 5     double x,y;  
 6 }a[N];  
 7 int cmpx(int t1,int t2){
 8     return a[t1].x<a[t2].x;    
 9 }  
10 int cmpy(int t1,int t2){
11     return a[t1].y>a[t2].y;  
12 }
13 int n,t[N],c1[N],cnt1,c2[N],cnt2;    
14 double dist(int t1,int t2){
15     return sqrt( (a[t1].x-a[t2].x)*(a[t1].x-a[t2].x)+(a[t1].y-a[t2].y)*(a[t1].y-a[t2].y)); 
16 }
17 double calc(int l,int r,int mid,double d){
18     sort(c1+1,c1+cnt1+1,cmpy);  
19     sort(c2+1,c2+cnt2+1,cmpy);  
20     int k=1;    
21     double ret=d;  
22     for(int i=1;i<=cnt1;i++) {
23         while (k<=cnt2 && a[c2[k]].y-a[c1[i]].y>d) k++; 
24         for(int j=k;j<=cnt2;j++)   
25             if( a[c1[i]].y-a[c2[j]].y<d)   
26                 ret=min(ret,dist(c1[i],c2[j]));  
27             else break;  
28     }
29     return ret; 
30 } 
31         
32 double close_dist(int l,int r){
33     if(l==r) return 1e9;    
34     if(l+1==r) return dist(t[l],t[r]);
35     int mid=(l+r)/2; 
36     double d1=close_dist(l,mid);  
37     double d2=close_dist(mid+1,r);  
38     double d=min(d1,d2);
39     cnt1=cnt2=0;   
40     for(int i=l;i<=mid;i++){
41         double dd=a[t[mid]].x-a[t[i]].x;  
42         if(dd<d && dd>=0) c1[++cnt1]=t[i];  
43     }      
44     for(int i=mid+1;i<=r;i++){
45         int dd=a[t[i]].x-a[t[mid]].x;  
46         if(dd<d && dd>=0) c2[++cnt2]=t[i];  
47     }  
48     
49     return calc(l,r,mid,d);
50 }     
51 int main(){
52     while (scanf("%d",&n)!=EOF){
53         if(n==0) break;  
54         for(int i=1;i<=n;i++)  
55             scanf("%lf%lf",&a[i].x,&a[i].y);  
56         for(int i=1;i<=n;i++) t[i]=i;  
57         sort(t+1,t+n+1,cmpx);  
58         printf("%0.2lf\n",close_dist(1,n)/2);  
59      }
 60      リターン 0 61 }
コードの表示

 

おすすめ

転載: www.cnblogs.com/ZJXXCN/p/11117777.html