分治算法求最近点对
?????http://acm.hdu.edu.cn/showproblem.php?pid=1007
???????? 先說下題意,很簡單,給n個點的坐標(biāo),求距離最近的一對點之間距離的一半。第一行是一個數(shù)n表示有n個點,接下來n行是n個點的x坐標(biāo)和y坐標(biāo),實數(shù)。
????? 這個題目其實就是求最近點對的距離。《算法導(dǎo)論》上有詳細(xì)講解,王曉東的書上也有代碼。主要思想就是分治。先把n個點按x坐標(biāo)排序,然后求左邊n/2個和右邊n/2個的最近距離,最后合并。合并要重點說一下,比較麻煩。
????? 首先,假設(shè)點是n個,編號為1到n。我們要分治求,則找一個中間的編號mid,先求出1到mid點的最近距離設(shè)為d1,還有mid+1到n的最近距離設(shè)為d2。這里的點需要按x坐標(biāo)的順序排好,并且假設(shè)這些點中,沒有2點在同一個位置。(若有,則直接最小距離為0了)。
????? 然后,令d為d1, d2中較小的那個點。如果說最近點對中的兩點都在1-mid集合中,或者mid+1到n集合中,則d就是最小距離了。但是還有可能的是最近點對中的兩點分屬這兩個集合,所以我們必須先檢測一下這種情況是否會存在,若存在,則把這個最近點對的距離記錄下來,去更新d。這樣我們就可以得道最小的距離d了。
????? 關(guān)鍵是要去檢測最近點對,理論上每個點都要和對面集合的點匹配一次,那效率還是不能滿足我們的要求。所以這里要優(yōu)化。怎么優(yōu)化呢?考慮一下,假如以我們所選的分割點mid為界,如果某一點的橫坐標(biāo)到點mid的橫坐標(biāo)的絕對值超過d1并且超過d2,那么這個點到mid點的距離必然超過d1和d2中的小者,所以這個點到對方集合的任意點的距離必然不是所有點中最小的。
????? 所以我們先把在mid為界左右一個范圍內(nèi)的點全部篩選出來,放到一個集合里。篩選好以后,當(dāng)然可以把這些點兩兩求距離去更新d了,不過這樣還是很慢,萬一滿足條件的點很多呢。這里還得繼續(xù)優(yōu)化。首先把這些點按y坐標(biāo)排序。假設(shè)排序好以后有cnt個點,編號為0到cnt-1。那么我們用0號去和1到cnt-1號的點求一下距離,然后1號和2到cnt-1號的點求一下距離。。。如果某兩個點y軸距離已經(jīng)超過了d,這次循環(huán)就可以直接break了,開始從下一個點查找了。
按照y值進(jìn)行升序排列后,還可以進(jìn)一步進(jìn)行優(yōu)化的,就是每次選取7個點就OK了,具體原因編程之美上面有介紹的。
for(i = 0 ; i < cnt ; ++i){int k = (i+7) > cnt ? cnt :(i+7); //只要選取出7個點(證明過程沒看懂) for(j = i+1 ; j < k ; ++j){if(p[a[j]].y - p[a[i]].y >= ans) //注意下標(biāo)索引break;ans = min(ans , dis(p[a[i]] , p[a[j]]));}}
總結(jié)
- 上一篇: N*N匹马,N个赛道,求出最快N匹马的解
- 下一篇: 随机数范围扩展方法总结