• 平面最近点对的算法实现


    平面最近点对的算法实现

    O(nlogn)

    平面最近点对是在谈到归并算法时常用的例子,其复杂度可以到达优秀的(O(nlogn));但当真正去实现这样的复杂度实际并不显然。

    算法核心思想:

    1. 对点集按照(x)坐标排序
    2. 分成两部分(S),(Q);分别求这两部分的最近点对,假设为(minl)
    3. 进行merge,主要考虑距离中点横坐标距离不超过(minl)的点集(M),最坏情况下(M)集合大小是(O(n));但我们只需对集合中每个元素元素比较8次(落在固定大小矩形上的点).所以复杂度(O(nlogn))

    实现问题:
    如何找到所需要比较的8个元素?

    就我翻阅的资料来看,还没有真正常数时间就能找到这8个元素的实现,所以很多实现的最坏情况的复杂度是(O(n^2))(也许均摊情况会好很多).

    这里给出(O(nlognlogn))的算法;
    思想:找到(M)集合元素后,按照(y)轴进行排序,这样只需向上比较8个点即可(常数个点)

    复杂度分析:
    (f(n) = 2f(n/2)+O(nlogn))
    master thereom:
    (O(nlogn^{k+1}) = O(nlognlogn))

    例题:hdu1007

    code
    
    /*
     * @Author: fridayfang
     * @Github: https://github.com/fridayfang
     * @LastEditors  : fridayfang
     * @Date: 2020-01-06 19:09:57
     * @LastEditTime : 2020-01-06 20:57:53
     */
    #include<bits/stdc++.h>
    using namespace std;
    #define mm(a,b) memset(a,b,sizeof(a))
    #define db(x) cout<<"["<<#x<<"]="<<x<<endl
    #define fast() ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0)
    
    const int maxn = 1e5+1000;
    int n;
    int selec[maxn];
    // vector<int> selec;
    struct point{
        double x,y;
        point(){}
        point(double _x,double _y){x=_x,y=_y;}
    }ps1[maxn],ps2[maxn];
    bool cmp1(const point& p1, const point&p2){
        if(p1.x<p2.x) return true;
        if(p1.x==p2.x&&(p1.y<p2.y)) return true;
        return false;
    }
    bool cmp2(const point& p1,const point& p2){
        if(p1.y<p2.y) return true;
        if(p1.y==p2.y&&(p1.x<p2.x)) return true;
        return false;
    }
    double getd(const point& p1, const point& p2){
        return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)+0.0);
        // return sqrt((ps1[i].x-ps1[j].x)*(ps1[i].x-ps1[j].x)+(ps1[i].y-ps1[j].y)*(ps1[i].y-ps1[j].y));
    }
    double _merge(int l,int mid,int r,double mm){
        int cnt = 0;
        double midx = ps1[mid].x;
        double minv = 1e10+10.0;
        for(int i=l;i<=r;i++){
            if(abs(ps1[i].x-midx)<mm){ps2[cnt].x = ps1[i].x, ps2[cnt].y = ps1[i].y, cnt++;}
        }
        sort(ps2,ps2+cnt, cmp2);
        for(int i=0;i<cnt;i++){
            for(int k=1;k<=8&&(i+k)<cnt;k++){
                minv = min(minv, getd(ps2[i],ps2[i+k]));
            }
        }
        return minv;
    }
    double getn(int l,int r){
        if(r-l==1){
            return getd(ps1[l],ps1[r]);
        }
        if(r-l==2){
            return min(min(getd(ps1[l],ps1[l+1]),getd(ps1[l+1],ps1[r])),getd(ps1[l],ps1[r]));
        }
        int mid = (l+r)>>1;
        double leftd = getn(l,mid);
        double rightd = getn(mid+1,r);
        double mm = min(leftd,rightd);
        // db(mm);
        mm = min(mm, _merge(l,mid,r,mm));
        // db(l);db(r);db(mm);
        return mm;
        
    }
    double solve(){
        return getn(0,n-1);
        
    }
    int main(){
        // fast();
        while(~scanf("%d",&n)&&n){
            for(int i=0;i<n;i++){
                scanf("%lf %lf",&ps1[i].x, &ps1[i].y);
                // cin>>ps1[i].x>>ps1[i].y;
                ps2[i].x = ps1[i].x; ps2[i].y = ps1[i].y;
            }
            sort(ps1,ps1+n, cmp1);
            sort(ps2,ps2+n, cmp2);
            printf("%.2lf
    ",solve()/2.0);
        }
    }
    
  • 相关阅读:
    NOI online2022题解
    【考试总结】20220331
    【考试总结】20220329
    【考试总结】20220327
    【考试总结】20220328
    【考试总结】20220326
    ElementUI使用vif控制tab标签显示遇到的Duplicate keys detected: 'xxx' 数据主键key重复
    ElementUI 的Tree Tree 菜单树形控件
    Element表格单元格的几种点击事件
    haproxy安装步骤及注意事项
  • 原文地址:https://www.cnblogs.com/fridayfang/p/12158919.html
Copyright © 2020-2023  润新知