分治演算法五(最近點對---杭電OJ 1007 Quoit Design)
阿新 • • 發佈:2019-01-11
1、問題描述
即給定座標系上N個點,找到距離最短的兩個點。
2、思路解析
----->如果直接利用兩兩點比較的話,複雜度太高,為O(n^2),會導致超時
----->簡化問題:考慮一維數軸上點的情況,如果對這些點排序O(nlgn),那麼最後只需要用O(n)時間就可以找到最小距離,所以總的時間複雜度就是O(nlgn)。
----->回到二維:是不是可以先排序再搜尋呢?如果仿照一維的情況,會出現什麼問題呢?
=====>>先試著根據 x 軸排序,此時平面上的資料點按照 x 軸已經排好了順序,那麼是不是簡單的遍歷就能找到最小距離呢?
=====>>二維情況下,距離不是單方面決定的,而是由x,y兩個座標一起決定的,在一個方向上距離最短,不代表最終結果距離最短
=====>>難道這樣做不行嗎?
=====>>可以順著這個思路做,但是要修正一下。採用分治的方法。先根據 x 軸對資料點排序,然後從中值點對陣列一分為二。分別找到左右兩個集合中的最短距離。
然後還有可能存在最短距離的位置就是兩個集合之間的區域。對於這個區域,可以把範圍限制在【mid - D , mid + D】之間以縮小範圍。同時對 y 軸排序,
找出範圍在D之內的點,這些點都是可能存在最小距離的區域點。
----->時間複雜度:T(n) = 2*T(n/2) + O(n) = O(nlgn)
/* file: closest */ /* 1、find the closet distance oftwo points */ /* 2、using divide and conquer algorithm */ /* 3、sorting the points by x-coordinate */ /* 4、divide the points into two sets by L: x = mid,where mid is the middle of the points's x-coordinate. set S1:on the left of line L set S2:on the right of line L */ /* 5、conquer the two sets S1 and S2, and find the minimum distance in set S1 and S2. D = min(S1,S2) */ /* 6、combine:the minimum distance can also be finded between set S1 and S2. the x-coordinate is limited in [mid-D,mid+D],and then sort the limited points by y-coordinate. therefore, the y-coordinate is limited in the length of D */ /* problem:HDU OJ 1007*/ #include <iostream> #include <algorithm> #include <cmath> using namespace std; #define MaxNum 100005 /*===================================== Point:struct of a point PointArray:input points PointY :y-coordinate sorting =======================================*/ struct Point { double x,y; }PointArray[MaxNum],PointY[MaxNum]; /*===================================== CmpX:compare of x-coordinate =======================================*/ bool CmpX(Point a,Point b) { return a.x < b.x; } /*===================================== CmpY:compare of y-coordinate =======================================*/ bool CmpY(Point a,Point b) { return a.y < b.y; } /*===================================== Minimun:return the minimum =======================================*/ inline double Minimun(double a, double b) { return (a < b) ? a : b; } /*===================================== Distance:return the distance between point a, b =======================================*/ inline double Distance(Point a, Point b) { double Px = a.x - b.x; double Py = a.y - b.y; return sqrt(Px * Px + Py * Py); } /*===================================== Closest:return the closest distance of the points =======================================*/ double Closest(int left, int right) { //middle of the array int mid = (left + right) >> 1; //Minimun distance double MinD; int i, j, count; //case of two points if((right - left) == 1) return Distance(PointArray[left], PointArray[right]); //case of three points else if((right - left) == 2) { MinD = Minimun(Distance(PointArray[left], PointArray[right]), Distance(PointArray[left + 1], PointArray[right])); return Minimun(Distance(PointArray[left], PointArray[left + 1]), MinD); } //conquer MinD = Minimun(Closest(left, mid), Closest(mid + 1, right)); //find the points of x-coordinate in [mid - MinD, mid + MinD] for(i = left, count = 0; i <= right; i++) if(fabs(PointArray[i].x - PointArray[mid].x) <= MinD) PointY[count++] = PointArray[i]; //sorting PointY by y-coordinate sort(PointY, PointY + count, CmpY); //Attention:==> for 2-D points,must using two-flod (for) to find the every possible point for(i = 0; i < count; i++) for(j = i + 1; j < count; j++) { if(fabs(PointY[i].y - PointY[j].y) >= MinD) break; MinD = Minimun(MinD, Distance(PointY[i], PointY[j])); } return MinD; } void main() { int N, i; double MinD; while(cin>>N,N) { for(i = 0; i < N; i++) scanf("%lf%lf",&PointArray[i].x,&PointArray[i].y); sort(PointArray, PointArray + N, CmpX); MinD = Closest(0,N-1); printf("%.2lf\n",MinD/2); } }