日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

分治应用--最近点对问题 POJ 3714

發布時間:2024/7/5 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 分治应用--最近点对问题 POJ 3714 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 1. 問題描述
    • 2. 解題思路
    • 3. 實現代碼
    • 4. POJ 3714

1. 問題描述

二維平面上有n個點,如何快速計算出兩個距離最近的點對?

2. 解題思路

  • 暴力做法是,每個點與其他點去計算距離,取最小的出來,復雜度O(n2)
  • 采用分治算法
  • 將數據點按照 x 坐標排序,找到中位點,過中位點劃線 x = mid_x 將數據分成2部分,遞歸劃分,直到兩個半邊只有1個或者2個數據,只有1個數據點,最短距離返回無窮大,有2個點直接返回2點的距離
  • 合并左右兩邊的結果,取左右兩邊的最短距離的較小值為 d = min{dl,dr},那么在 x = mid_x 的 ± d 范圍內的左右點對才有可能距離比 d 更小(好理解)
  • 對這個范圍內的點,再按照 y 坐標排序,查找兩個點的 y 差值小于 d 的點對(重點在這里,見下面分析),計算其距離是否比 d 更小

    假如在這個范圍內的有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,誰幫忙看下。測試樣例輸出是一樣的。

    /*** @description: poj3714求解最近的核電站距離* @author: michael ming* @date: 2019/7/6 0:09* @modified by: */ #include<iomanip> #include <iostream> #include <cmath> #include <vector> #include <algorithm> #define DBL_MAX 1.7976931348623158e+308 using namespace std; class Point//點 { public:int id;int x, y;Point(int index, int x0, int 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(){int x, y;cin >> numOfPoint;for(int i = 0; i < numOfPoint; ++i){cin >> x >> y;points_vec.push_back(Point(0,x,y));//生成站點的動態數組(0表示站)}for(int i = 0; i < numOfPoint; ++i){cin >> x >> y;points_vec.push_back(Point(1,x,y));//加入人的位置(1表示人)}}double dist(const Point &a, const Point &b){if(a.id == b.id)return DBL_MAX;//相同的類型,返回很大的數int dx = a.x - b.x;int dy = a.y - b.y;return sqrt(double(dx*dx + dy*dy));//返回兩點之間的距離}double calcDist(size_t left, size_t right){if(left == right)//一個點,返回無窮大return DBL_MAX;if(left+1 == right)//兩個點,直接計算距離{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 = DBL_MAX, d;distance = min(distance,calcDist(left,mid));//遞歸劃分左邊distance = min(distance,calcDist(mid+1,right));//遞歸劃分右邊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.push_back(Point(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;}}}return distance;}double closestDist()//調用分治求解{size_t num = points_vec.size();return calcDist(0,num-1);}}; int main() {int times;cin >> times;while (times--){ClosestPoint cp;cout << fixed << setprecision(3) << cp.closestDist() << endl;}return 0; }

    總結

    以上是生活随笔為你收集整理的分治应用--最近点对问题 POJ 3714的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。