转载 - 最近对问题
之前看過,可是當(dāng)時沒有細(xì)看,今天在網(wǎng)上搜了一下,看了一下別人的思路,畢竟這也是一類問題的經(jīng)典。過一段時間再將自己對其認(rèn)識總結(jié)。現(xiàn)在先轉(zhuǎn)載別人的思路。
出處:http://blog.csdn.net/sd6264456/article/details/9318861
給n個點(diǎn)的坐標(biāo),求距離最近的一對點(diǎn)之間距離的一半。第一行是一個數(shù)n表示有n個點(diǎn),接下來n行是n個點(diǎn)的x坐標(biāo)和y坐標(biāo),實(shí)數(shù)。
???? 這個題目其實(shí)就是求最近點(diǎn)對的距離。主要思想就是分治。先把n個點(diǎn)按x坐標(biāo)排序,然后求左邊n/2個和右邊n/2個的最近距離,最后合并。合并要重點(diǎn)說一下,比較麻煩。
???? 首先,假設(shè)點(diǎn)是n個,編號為1到n。我們要分治求,則找一個中間的編號mid,先求出1到mid點(diǎn)的最近距離設(shè)為d1,還有mid+1到n的最近距離設(shè)為 d2。這里的點(diǎn)需要按x坐標(biāo)的順序排好,并且假設(shè)這些點(diǎn)中,沒有2點(diǎn)在同一個位置。(若有,則直接最小距離為0了)。
???? 然后,令d為d1, d2中較小的那個點(diǎn)。如果說最近點(diǎn)對中的兩點(diǎn)都在1-mid集合中,或者mid+1到n集合中,則d就是最小距離了。但是還有可能的是最近點(diǎn)對中的兩點(diǎn)分 屬這兩個集合,所以我們必須先檢測一下這種情況是否會存在,若存在,則把這個最近點(diǎn)對的距離記錄下來,去更新d。這樣我們就可以得道最小的距離d了。
??? 關(guān)鍵是要去檢測最近點(diǎn)對,理論上每個點(diǎn)都要和對面集合的點(diǎn)匹配一次,那效率還是不能滿足我們的要求。所以這里要優(yōu)化。怎么優(yōu)化呢?考慮一下,假如以我們所 選的分割點(diǎn)mid為界,如果某一點(diǎn)的橫坐標(biāo)到點(diǎn)mid的橫坐標(biāo)的絕對值超過d1并且超過d2,那么這個點(diǎn)到mid點(diǎn)的距離必然超過d1和d2中的小者,所 以這個點(diǎn)到對方集合的任意點(diǎn)的距離必然不是所有點(diǎn)中最小的。
??? 所以我們先把在mid為界左右一個范圍內(nèi)的點(diǎn)全部篩選出來,放到一個集合里。篩選好以后,當(dāng)然可以把這些點(diǎn)兩兩求距離去更新d了,不過這樣還是很慢,萬一 滿足條件的點(diǎn)很多呢。這里還得繼續(xù)優(yōu)化。首先把這些點(diǎn)按y坐標(biāo)排序。假設(shè)排序好以后有cnt個點(diǎn),編號為0到cnt-1。那么我們用0號去和1到cnt- 1號的點(diǎn)求一下距離,然后1號和2到cnt-1號的點(diǎn)求一下距離。。。如果某兩個點(diǎn)y軸距離已經(jīng)超過了d,這次循環(huán)就可以直接break了,開始從下一個 點(diǎn)查找了.
?
1 #include <cmath> 2 #include <algorithm> 3 #include <iostream> 4 #include <string.h> 5 using namespace std; 6 struct node 7 { 8 double x,y; 9 }a[100005]; 10 int c[100005]; 11 double cmpy(int t1,int t2) 12 { 13 return a[t1].y<a[t2].y; 14 } 15 bool cmp(node t1,node t2) 16 { 17 return t1.x<t2.x; 18 } 19 double dis(node t1,node t2) 20 { 21 return sqrt((t1.x-t2.x)*(t1.x-t2.x)+(t1.y-t2.y)*(t1.y-t2.y)); 22 } 23 double min(double t1,double t2) 24 { 25 return t1<t2?t1:t2; 26 } 27 double find(int left,int right) 28 { 29 if(left+1==right) 30 return dis(a[left],a[right]); 31 if(left+2==right) 32 return min(dis(a[left],a[right]),min(dis(a[left],a[left+1]),dis(a[left+1],a[right]))); 33 int mid=(left+right)>>1; 34 double ans=min(find(left,mid),find(mid+1,right)); 35 int i,j,cnt=0; 36 for(i=left;i<=right;i++) 37 { 38 if(a[i].x>=a[mid].x-ans&&a[i].x<=a[mid].x+ans) 39 c[cnt++]=i; 40 } 41 sort(c,c+cnt,cmpy); 42 for(i=0;i<cnt;i++) 43 { 44 for(j=i+1;j<cnt;j++) 45 { 46 if(a[c[j]].y-a[c[i]].y>=ans) 47 break; 48 ans=min(ans,dis(a[c[i]],a[c[j]])); 49 } 50 } 51 return ans; 52 53 } 54 int main() 55 { 56 int n,i; 57 while(cin>>n,n) 58 { 59 for(i=0;i<n;i++) 60 { 61 cin>>a[i].x>>a[i].y; 62 } 63 std::sort(a,a+n,cmp); 64 printf("%.2lf\n",find(0,n-1)/2); 65 } 66 return 0; 67 }?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/sineatos/p/3229107.html
總結(jié)
以上是生活随笔為你收集整理的转载 - 最近对问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一款jq的计时器
- 下一篇: IText 生成页脚页码