[转] 最近点对距离问题
轉(zhuǎn)載自:http://www.cnblogs.com/king1302217/archive/2010/07/08/1773413.html
?
求點集中的最近點對有以下兩種方法:
設(shè)p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n個點構(gòu)成的集合S,設(shè)計算法找出集合S中距離最近的點對。
?
1、蠻力法(適用于點的數(shù)目比較小的情況下)
???? 1)算法描述:已知集合S中有n個點,一共可以組成n(n-1)/2對點對,蠻力法就是對這n(n-1)/2對點對逐對進行距離計算,通過循環(huán)求得點集中的最近點對:
???? 2)代碼描述:
double MinDistance = double.maxvalue;? //設(shè)置一個MinDistance存儲最近點對的距離,初始值為無窮大
int PointIndex1,PointIndex2; //設(shè)置PointIndex1,PointIndex2分別存儲最近點對的兩個點編號
for (i=1; i< n; i++)??? //循環(huán)計算n(n-1)/2對點對的距離 {
???? for (j=i+1; j<=n; j++) ???? {
?????????? double PointDistance = Distance(S[i],S[j]);?? //求得point i和point j之間的距離
?????????? if PointDistance < MinDistance;? //如果當前點對距離小于最小點對距離,則設(shè)置最小點對距離等于當前點對距離
?????????? {
???????????????? MinDistance = PointDistance;
???????????????? PointIndex1 = i;
???????????????? PointIndex2 = j;
??????????? }
?????? }
}
????? }? ???? 3)算法時間復雜度:算法一共要執(zhí)行 n(n-1)/2次循環(huán),因此算法復雜度為O(n2)
?
2、分治法
???? 1)算法描述:已知集合S中有n個點,分治法的思想就是將S進行拆分,分為2部分求最近點對。算法每次選擇一條垂線L,將S拆分左右兩部分為SL和SR,L一般取點集S中所有點的中間點的x坐標來劃分,這樣可以保證SL和SR中的點數(shù)目各為n/2,
(否則以其他方式劃分S,有可能導致SL和SR中點數(shù)目一個為1,一個為n-1,不利于算法效率,要盡量保持樹的平衡性)
依次找出這兩部分中的最小點對距離:δL和δR,記SL和SR中最小點對距離δ = min(δL,δR),如圖1:
???
???? 以L為中心,δ為半徑劃分一個長帶,最小點對還有可能存在于SL和SR的交界處,如下圖2左圖中的虛線帶,p點和q點分別位于SL和SR的虛線范圍內(nèi),在這個范圍內(nèi),p點和q點之間的距離才會小于δ,最小點對計算才有意義。
????
?
?
?
?
?
Figure 2?
?
????? 對于SL虛框范圍內(nèi)的p點,在SR虛框中與p點距離小于δ的頂多只有六個點,就是圖二右圖中的2個正方形的6的頂點。這個可以反推證明,如果右邊這2個正方形內(nèi)有7個點與p點距離小于δ,例如q點,則q點與下面正方形的四個頂點距離小于δ,則和δ為SL和SR中的最小點對距離相矛盾。因此對于SL虛框中的p點,不需求出p點和右邊虛線框內(nèi)所有點距離,只需計算SR中與p點y坐標距離最近的6個點,就可以求出最近點對,節(jié)省了比較次數(shù)。
(否則的話,最壞情形下,在SR虛框中有可能會有n/2個點,對于SL虛框中的p點,每次要比較n/2次,浪費了算法的效率)
???? 代碼描述:
???? 1)對點集S的點x坐標和y坐標進行升序排序,獲得點集Sx和Sy
???? 2)令δ=∞;?? //δ為最小點位距離
???? 3)Divide_conquer(Sx,Sy,δ)? //分治法
???????????? if (Sx.count=1) then δ=∞;?? //如果Sx中只有一個點,則δ=∞
????????????????? return δ;
???????????? else if(Sx.count=2 and d(Sx.[0],Sx.[1])<δ) //如果Sx中只有2個點,則δ為兩點之間距離
?????????????????? δ=d(Sx.[0],)Sx.[1]);?
?????????????????? return δ;
???????????? else??? //如果Sx中多于2個點,則將Sx,Sy分治,以中心點畫線,將Sx分為左右兩部分SxL和SxR,Sy分為SyL和SyR
?????????????????? j1=1,j2=1,k1=1,k2=1;
?????????????????? mid = Sx.count/2;? //mid為Sx中的中間點點號
?????????????????? L = Sx.[mid].x;???? //L為Sx中的中間點x坐標
?????????????????? for(i=1,i<Sx.count,i++)
?????????????????? {
???????????????????????? if(i<=mid)??? //將Sx中間線以左地方的點存入到SxL,新數(shù)組保持原來的升序性質(zhì)
??????????????????????????????? SxL[k1] = Sx[i]?? k1++;
???????????????????????? else?? //將Sx中間線以右的地方的點存入到SxR,新數(shù)組保持原來的升序性質(zhì)
??????????????????????????????? SxR.count[k2] = Sx[i]?? k2++;
???????????????????????? if(Sy[i].x <L)?? //將Sy中間線以左地方的點存入到SyL,新數(shù)組保持原來的升序性質(zhì)
??????????????????????????????? SyL[j1] = Sx[i]?? j1++;
?
???????????????????????? else?? //將Sy中間線以右地方的點存入到SyR,新數(shù)組保持原來的升序性質(zhì)
?
??????????????????????????????? SyR[j2] = Sx[i]?? j2++;
?
?
?????????????????? }
????????????? δL = Divide_conquer(SxL,SyL,δ);??? //獲取Sx中的的最小點位距離δL
?
????????????? δR = Divide_conquer(SxR,SyR,δ);?? //獲取Sy中的的最小點位距離δR
????????????? δ= min (δL,δR);
????????????? δ=merge(SyL,SyR,δ);?? //獲Sx中Sy交界處的最小點位距離,并綜合 δL和δR 求出點集的最小點位距離δ
????? return δ;
?
????? 函數(shù)merge(SyL,SyR,δ)
????? merge(SyL,SyR,δ)
????? {
????????? i1=1,i2=1;
????????? for(i=1,i<SyL.count,i++)?? //獲取SyL中在左邊虛框(距離小于δ)內(nèi)的點,存入到S'yL中,新數(shù)組保持原來的升序性質(zhì)
????????? {
????????????? if(SyL[i].x>L-δ)
????????????????? then S'yL[i1]= SyL[i], i1++,
?????????? }
????????? for(i=1,i<SyR.count,i++)? //獲取SyR中在右邊虛框(距離小于δ)內(nèi)的點,存入到S'yR中,新數(shù)組保持原來的升序性質(zhì)
????????? {
????????????? if(SyR[i].x<L+δ)
????????????? then S'yR[i2]= SyR[i], i2++,
????????? }
?
????????? t=1;
????????? for(i=1,i<S'yL.count,i++)
?????????? {?????
??????????????? while(S'yR[t].y< S'yL[t].y and t < SyR.count)? //獲取點集S'yR內(nèi)距離點S'yL[t]y坐標最接近的點號
??????????????? { t++; }
??????????????? for( j= max(1,t-3), j<=min(t+3,S'yR.count),j++)?? //計算S'yR中的點與S'yL[t]y坐標相鄰的六個點的距離
??????????????? {
????????????????????? if(d(S'yL[i],S'yL[j])<δ)??? //如果前兩點之間距離小于δ
????????????????????? then δ = d(S'yL[i],S'yL[j]);?? //則最小點位距離δ為當前兩點之間距離
??????????????? }
????????? return δ
????? }
?
3)算法時間復雜度:
????? 首先對點集S的點x坐標和y坐標進行升序排序,需要循環(huán)2nlogn次,復雜度為O(2nlogn)
????? 接下來在分治過程中,對于每個S'yL中的點,都需要與S'yR中的6個點進行比較
??????????? O(n)= 2O(n/2) + (n/2)*6? (一個點集劃分為左右兩個點集,時間復雜度為左右兩個點集加上中間區(qū)域運算之和)
????? 其解為O(n)< O(3nlogn)
???? 因此總的時間復雜度為O(3nlogn),比蠻力法的O(n2)要高效。
?
?
例題:http://acm.hdu.edu.cn/showproblem.php?pid=1007
參考代碼:http://www.cnblogs.com/hate13/p/4160111.html
轉(zhuǎn)載于:https://www.cnblogs.com/hate13/p/4160056.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的[转] 最近点对距离问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于JavaScript的数组随机排序
- 下一篇: webAPI token验证