算法分析与设计——分治法最近点对
分治法最近點對
分治法
分治法將一個難以直接解決的大問題劃分成一些規模較小的子問題,分別求解各個子問題,再合并子問題的解得到原問題的解。
一般來說,分治法的求解過程由以下三個階段組成:
最近點對問題
問題描述
設p1=(x1,y1),p2=(x2,y2),···,pn=(xn,yn)是平面上n個點構成的集合S,最近點對問題就是找出集合S中距離最近的點對。嚴格地說,最接近的點對可能多于一個,簡單起見,找出一個即可。
應用實例
假設在一個金屬片上鉆n個大小一樣的洞,如果洞的距離太近,金屬就可能會斷裂??梢酝ㄟ^任意兩個洞的最小距離來估算金屬斷裂的概率。這種最小距離問題實際上也就是最近點對問題。
想法
最近點對的分治策略如下:
(1)劃分:將集合S分成兩個子集S1和S2根據平衡子問題原則,每個子集中大約有n/2個點,設集合S的最近對是pi和pj,則會出現以下三種情況:
(2)求解子問題:對于劃分階段的情況1和情況2可遞歸求解,如果最近對分別在兩個子集中,在后邊做討論。
(3)合并:比較在劃分階段三種情況下的最近點對,取三者之中距離較小者為原問題的解。
下面討論劃分階段的情況3:
為了將平面上的點集S分割為點的個數大致相同的兩個集合,選取垂直線x=m來作分割線,其中m為S中各點x坐標的中位數。由此將S分割為S1和S2。遞歸地在S1和S2中求解最近對問題,分別得到S1中的最近距離d1和S2中的最近距離d2,令d=min(d1,d2。若S的最近對(p,q)之間的距離小于d,則p和q必定分屬于集合S1和S2。那么,不妨設p∈S1,q∈S2,則p和q距離直線x=m的距離均小于d,所以,可以將求解限制在以x=m為中心,寬為2d的垂直帶P1和P2中,垂直帶之外的任何點對之間的距離都一定大于d。
假設點p(x,y)是集合P1和P2中y坐標最小的點,則點p可能在P1中也可能在P2中,現在需要找出來和點p之間小于d的點,顯然這樣的點的y坐標一定位于區間[y,y+d]之間,而且這樣的點不會超過8個,因為P1和P2中點的相互之間的距離至少為d,如下圖所示。
所以,可以將P1和P2中的點按照y坐標升序排列,順序地處理P1和P2中的點p(x,y),在y坐標區間[y,y+d]內最多取出8個候選點,計算它們和點p之間的距離。
算法
簡單起見,假設點集S已按照x坐標升序排列,偽代碼描述如下:
輸入:按x坐標升序排列的n個點的集合S
輸出:最近點對的距離
源代碼
#include<iostream> #include<math.h> #include<stdlib.h>using namespace std;int M[2], N[2], P[2], Q[2];typedef struct point {double x,y; }point;void Qsortx(point *A, int low, int high){double tempx, tempy;int i = low, j = high;if(low < high){tempx = A[i].x;tempy = A[i].y;while(i != j){while(j > i && A[j].x > tempx)j--;if(i < j){A[i].x = A[j].x;A[i].y = A[j].y;i++;}while(i < j && A[i].x < tempx)i++;if(i<j){A[j].x = A[i].x;A[j].y = A[i].y;j--;}A[i].x = tempx;A[i].y = tempy;Qsortx(A,low,i-1);Qsortx(A,i+1,high);}}} void Qsorty(point *A, int low, int high){double tempx, tempy;int i = low, j = high;if(low < high){tempx = A[i].x;tempy = A[i].y;while(i != j){while(j > i && A[j].y > tempy)j--;if(i<j){A[i].x = A[j].x;A[i].y = A[j].y;i++;}while(i < j && A[i].y < tempy)i++;if(i < j){A[j].x = A[i].x;A[j].y = A[i].y;j--;}A[i].x = tempx;A[i].y = tempy;Qsorty(A,low,i-1);Qsorty(A,i+1,high);}}}double d(point p1, point p2){double dx, dy, dm;dx = p1.x - p2.x;dy = p1.y - p2.y;dm = pow(dx,2) + pow(dy,2);return sqrt(dm);}void printarry(point *points, int n){for(int i=0; i < n; i++){cout<<"("<<points[i].x<<","<<points[i].y<<")";}cout<<endl;cout<<endl;}double cp(point *S,point *Y,int low,int high){int e, r, mid, k = 0, n=high-low+1;double x0, min, minl, minr, minlr;point T[n];mid = (low + high) / 2;x0 = S[mid].x;if(n == 2){return d(S[low], S[high]);M[0] = low;M[1] = high;}if(n == 3){double d1, d2, d3;d1 = d(S[low], S[low+1]);d2 = d(S[low], S[low+2]);d3 = d(S[low+1], S[low+2]);if(d1<=d2){min = d1;M[0] = low;M[1] = low+1;}else{min = d2;M[0] = low;M[1] = low+2;}if(min > d3){min = d3;M[0] = low + 1;M[1] = low + 2;}}else{minl = cp(S, Y, low, mid);N[0] = M[0];N[1] = M[1];minr = cp(S, Y, mid+1, high);P[0] = M[0];P[1] = M[1];if(minl <= minr){min = minl;Q[0] = N[0];Q[1] = N[1];}else{min = minr;Q[0] = P[0];Q[1] = P[1];}for(int i = 0; i < n; i++){if(fabs(Y[i].x-x0) <= min){T[k].x = Y[i].x;T[k].y = Y[i].y;k++;}}minlr = 2*min;for(int i=0;i<k;i++){int jj;if((i+7) < k)jj=i+7;else jj = k;for(int j = i+1; j < jj; j++){double dd = d(T[i], T[j]);if(dd<minlr){minlr = dd;e = i;r = j;}}}if(minlr < min){min = minlr;for(int i = 0; i < n; i++){if(T[e].x == S[i].x && T[e].y == S[i].y)Q[0] = i;}for(int j = 0; j < n; j++){if(T[r].x == S[j].x && T[r].y == S[j].y)Q[1] = j;}}}return min;}int main(){int n;int f = 1;double mini;cout<<"請輸入點的個數:"<<endl;while(f){cin>>n;if(n <= 3)cout<<"非法輸入!請重新輸入:"<<endl;else{f = 0;break;}}point S[n], Y[n];cout<<"請輸入這"<<n<<"個點的坐標:"<<endl;for(int i = 0; i < n; i++){cin>>S[i].x>>S[i].y;}Qsortx(S, 0, n-1);for(int i = 0; i < n; i++){Y[i].x = S[i].x;Y[i].y = S[i].y;}Qsorty(Y, 0, n-1);printarry(S, n);printarry(Y, n);mini = cp(S, Y, 0, n-1);cout<<"最近的兩個點是:"<<endl;cout<<"("<<S[Q[0]].x<<","<<S[Q[0]].y<<")"<<"<----->"<<"("<<S[Q[1]].x<<","<<S[Q[1]].y<<")"<<endl;cout<<endl;cout<<"最近點對的距離為:"<<mini<<endl;system("pause");return 0;}算法分析
應用分治算法求解含有n個點的最近對問題,由于劃分階段的情況1和情況2可遞歸求解,情況3的時間代價是O(n),合并子問題解的時間代價是O(1),則算法的時間復雜度可由下邊的遞推式表示:
可得T(n)=O(nlogn)。
總結
以上是生活随笔為你收集整理的算法分析与设计——分治法最近点对的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 道路检测 | SNE-RoadSeg论文
- 下一篇: 简述PyTorch