分治应用--最近点对问题 POJ 3714
生活随笔
收集整理的這篇文章主要介紹了
分治应用--最近点对问题 POJ 3714
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 1. 問題描述
- 2. 解題思路
- 3. 實現代碼
- 4. POJ 3714
1. 問題描述
二維平面上有n個點,如何快速計算出兩個距離最近的點對?
2. 解題思路
- 暴力做法是,每個點與其他點去計算距離,取最小的出來,復雜度O(n2)
- 采用分治算法
假如在這個范圍內的有1,2,3,4,5,6六個點(按 y 坐標排序),尋找距離小于 d 的點對,如果暴力查找,復雜度還是 n2,我們可以看出點4只有可能在其上下y坐標 ± d 的范圍內找到滿足距離小于 d 的點匹配,點1和點4不可能距離小于 d,左邊的點最多可以有4個右邊的點使得其距離小于 d
所以,步驟3是O(n)復雜度。
T(1) = 1;T(n) = 2*T(n/2)+n;高中數學即可求得T(n)是O(nlogn)的復雜度。
3. 實現代碼
/*** @description: 2維平面尋找距離最近的點對(分治)* @author: michael ming* @date: 2019/7/4 23:16* @modified by: */ #include <iostream> #include <cmath> #include <vector> #include <ctime> #include <algorithm> #define LEFT_BOUND 0.0 #define RIGHT_BOUND 100.0 #define LOWER_BOUND 0.0 #define UPPER_BOUND 100.0 //隨機點的范圍 using namespace std; class Point//點 { public:int id;double x, y;Point(int index, double x0, double y0):id(index),x(x0),y(y0){} }; typedef vector<Point> PointVec; bool compx(const Point &a, const Point &b) {if(a.x != b.x)return a.x < b.x;return a.y < b.y; } bool compy(const Point &a, const Point &b) {return a.y < b.y; }class ClosestPoint {PointVec points_vec;int numOfPoint; public:ClosestPoint(){srand(unsigned(time(0)));double x, y;cout << "請輸入測試點個數,將隨機生成散點:";cin >> numOfPoint;for(int i = 0; i < numOfPoint; ++i){x = LEFT_BOUND + (double)rand()/RAND_MAX *(RIGHT_BOUND-LEFT_BOUND);y = LOWER_BOUND + (double)rand()/RAND_MAX *(UPPER_BOUND-LOWER_BOUND);cout << i+1 << " (" << x << "," << y << ")" << endl;points_vec.emplace_back(i+1,x,y);//生成點的動態數組}}double dist(const Point &a, const Point &b){double dx = a.x - b.x;double dy = a.y - b.y;return sqrt(dx*dx + dy*dy);//返回兩點之間的距離}void bfCalDist()//暴力求解{size_t num = points_vec.size();if(num <= 1){cout << "輸入個數<=1 !!!" << endl;return;}int i, j, s, t;double distance = RAND_MAX, d;for(i = 0; i < num; ++i)for(j = i+1; j < num; ++j){d = dist(points_vec[i], points_vec[j]);if(d < distance){distance = d;s = points_vec[i].id;t = points_vec[j].id;}}cout << "點" << s << "到點" << t << "的距離最小:" << distance << endl;}double calcDist(size_t left, size_t right, size_t &s, size_t &t){if(left == right)//一個點,返回無窮大return RAND_MAX;if(left+1 == right)//兩個點,直接計算距離{s = points_vec[left].id;t = points_vec[right].id;return dist(points_vec[left],points_vec[right]);}sort(points_vec.begin()+left,points_vec.begin()+right+1,compx);//把點群按照x排序size_t mid = (left+right)/2;double mid_x = points_vec[mid].x;double distance = RAND_MAX, d;distance = min(distance,calcDist(left,mid,s,t));//遞歸劃分左邊distance = min(distance,calcDist(mid+1,right,s,t));//遞歸劃分右邊size_t i, j, k = 0;PointVec temp;//存儲臨時點(在mid_x左右d范圍內的)for(i = left; i <= right; ++i){if(fabs(points_vec[i].x-mid_x) <= distance){temp.emplace_back(points_vec[i].id,points_vec[i].x,points_vec[i].y);k++;}}sort(temp.begin(),temp.end(),compy);//再把范圍內的點,按y排序for(i = 0; i < k; ++i){for(j = i+1; j < k && temp[j].y-temp[i].y < distance; ++j){//在臨時點里尋找距離更小的,內層循環最多執行不超過4次就會退出d = dist(temp[i],temp[j]);if(d < distance){distance = d;s = temp[i].id;t = temp[j].id;}}}return distance;}void closestDist()//調用分治求解{size_t num = points_vec.size();if(num <= 1){cout << "輸入個數<=1 !!!" << endl;return;}size_t s, t; s = t = 0;//記錄起終點double d = calcDist(0,num-1,s,t);cout << "點" << s << "到點" << t << "的距離最小:" << d << endl;}}; int main() {ClosestPoint cp;clock_t start, end;cout << "方法1,暴力求解:" << endl;start = clock();cp.bfCalDist();end = clock();cout << "耗時:" << (double)(end - start) << "ms." << endl;cout << "-------------------" << endl;cout << "方法2,分治求解:" << endl;start = clock();cp.closestDist();end = clock();cout << "耗時:" << (double)(end - start) << "ms." << endl;return 0; }4. POJ 3714
http://poj.org/problem?id=3714
相同的問題,只是數據位置分為2類(人,核電站),計算距離時,需判斷是不同的類,否則返回一個很大的數。
以下代碼顯示Wrong Answer,誰幫忙看下。測試樣例輸出是一樣的。
總結
以上是生活随笔為你收集整理的分治应用--最近点对问题 POJ 3714的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: andriod studio 运行 无结
- 下一篇: 01.神经网络和深度学习 W1.深度学习