• 分治法求平面最近点对


    题意

    Here

    思考

    之前考分治的时候有一道题,要用到 (O(nlogn)) 求平面最近点对,然而当时我不会……现在写篇博客回顾一下。

    平面上 (n) 个点,让我们求最近点对,最朴素的想法是枚举,复杂度 (O(n^2))

    这样是显然过不了 (1e5) 的数据的,同时我们也发现对于一个点而言,我们计算了许多无用的情况,如何优化?

    分治思路:
    首先我们将所有点按横坐标排序,选择中位点的横坐标为轴,将整个平面分成两半,那么答案可以变为:

    (min() 左半平面上点对的最近距离,右半平面上点对的最近距离,左半和右半平面各选一个点组成的最短距离 ())

    重点的优化则在求第三个最近距离上,我们设左右半边点对距离的最小值为 (d),那么如果两点横坐标绝对值超过 (d) 我们就可以不计算了,纵坐标也同理。具体实现则是在分治内再排序一遍,总体复杂度 (O(nlog^2n)),如果排序的时候使用归并排序可以将复杂度降为 (O(nlogn))

    代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef double D;
    const int N = 200020;
    int tmp[N], n;
    struct node{
        D x, y;
    }P[N];
    D sqr(D x){
        return x * x;
    }
    D calc(int a, int b){
        return sqrt( sqr(P[a].x - P[b].x) + sqr(P[a].y - P[b].y) );
    }
    bool cmp(node a, node b){
        return a.x == b.x ? a.y < b.y : a.x < b.x;
    }
    bool cmp2(int x, int y){
        return P[x].y < P[y].y;
    }
    D solve(int l, int r){
        int cnt = 0; double d = 10000000;
        if(l == r) return 100000000;
        if(l + 1 == r) return calc(l, r);
        int mid = (l + r) >> 1;
        d = min( solve(l, mid), d );
        d = min( solve(mid+1, r), d);
        for(int i=l; i<=r; i++){
            if( fabs(P[mid].x - P[i].x) <= d){
                tmp[++cnt] = i;
            }
        }
        sort(tmp+1, tmp+cnt+1, cmp2);//这里的sort复杂度会多一个log
        for(int i=1; i<=cnt; i++){
            for(int j=i+1; j<=cnt && P[tmp[j]].y - P[tmp[i]].y < d; j++){
                double d1 = calc(tmp[i], tmp[j]);
                d = min(d, d1);
            }
        }
        return d;
    }
    int main(){
        cin >> n;
        for(int i=1; i<=n; i++){
            cin >> P[i].x >> P[i].y;
        }
        sort(P+1, P+n+1, cmp);
        cout << fixed << setprecision(4) << solve(1, n);
        return 0;
    }
    
    

    总结

    解法还是很妙的,主要是对求解过程可行性剪枝,这种分治思想也很值得学习。

  • 相关阅读:
    DVWA实验之Brute Force(暴力破解)- Low
    《Web安全攻防 渗透测试实战指南 》 学习笔记 (五)
    Bugku-web进阶之phpcmsV9(一个靶机而已,别搞破坏。flag在根目录里txt文件里)
    Bugku-CTF社工篇之简单的社工尝试
    Bugku-CTF社工篇之王晓明的日记
    Bugku-CTF社工篇之社工进阶
    Bugku-CTF社工篇之简单的个人信息收集
    Bugku-CTF社工篇之信息查找
    Bugku-CTF社工篇之密码
    Bugku-CTF之login3(SKCTF)(基于布尔的SQL盲注)
  • 原文地址:https://www.cnblogs.com/alecli/p/9917903.html
Copyright © 2020-2023  润新知