zoukankan      html  css  js  c++  java
  • HDU 1007 Quoit Design 平面内最近点对

    http://acm.hdu.edu.cn/showproblem.php?pid=1007

    上半年在人人上看到过这个题,当时就知道用分治但是没有仔细想...

    今年多校又出了这个...于是学习了一下平面内求最近点对的算法...算导上也给了详细的说明

    虽然一看就知道直接用分治O(nlogn)的算法 , 但是平面内最近点对的算法复杂度证明我看了一天也没有完全看明白...

    代码我已经做了一些优化...但肯定还能进一步优化..我是2s漂过的非常惭愧...(甚至优化以后时间还多了...不明白原因

    /********************* Template ************************/
    #include <set>
    #include <map>
    #include <list>
    #include <cmath>
    #include <ctime>
    #include <deque>
    #include <queue>
    #include <stack>
    #include <bitset>
    #include <cstdio>
    #include <string>
    #include <vector>
    #include <cassert>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <fstream>
    #include <numeric>
    #include <iomanip>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    
    #define EPS         1e-8
    #define MAXN        (int)1e5+5
    #define MOD         (int)1e9+7
    #define PI          acos(-1.0)
    #define INF         (1<<30)
    #define max(a,b)    ((a) > (b) ? (a) : (b))
    #define min(a,b)    ((a) < (b) ? (a) : (b))
    #define max3(a,b,c) (max(max(a,b),c))
    #define min3(a,b,c) (min(min(a,b),c))
    #define BUG         cout<<" BUG! "<<endl;
    #define L(t)        (t << 1)
    #define R(t)        (t << 1 | 1)
    #define Mid(a,b)    ((a + b) >> 1)
    #define lowbit(a)   (a & -a)
    #define FIN         freopen("out.txt","w",stdout)
    #pragma comment     (linker,"/STACK:102400000,102400000")
    
    // typedef long long LL;
    // typedef unsigned long long ULL;
    // typedef __int64 LL;
    // typedef unisigned __int64 ULL;
    // int gcd(int a,int b){ return b?gcd(b,a%b):a; }
    // int lcm(int a,int b){ return a*b/gcd(a,b); }
    
    /*********************   F   ************************/
    struct point
    {
        double x,y;
        int pos;
        point(double a = 0,double b = 0,int c = 0){
            x = a ; y = b ; pos = c;
        }
    }p[MAXN],tmp[MAXN];
    int n ;
    
    bool cmp(point a,point b){
        if(a.x == b.x) return a.y < b.y;
        return a.x < b.x;
    }
    
    bool cmp1(point a,point b){
        return a.y < b.y;
    }
    double dist(point a ,point b){
        return sqrt((double)((a.x-b.x) * (a.x-b.x) + (a.y-b.y) * (a.y-b.y)));
    }
    
    /*
     *  二维空间找最近点对
     *  返回排序后点位置的pair<int,int>
     */
    pair<int,int> Closest_Pair(int l ,int r){
        if(l == r || l+1 == r) return make_pair(l,r); //1个点,2个点 直接return;
        int m = Mid(l,r);       // (l+r)/2
        pair<int,int> dl = Closest_Pair(l,m);
        pair<int,int> dr = Closest_Pair(m+1,r);
        double ldis,rdis;       //左部分的最值 右部分的最值
        double ans_dis;         //左中右三部分最值
    
        if(dl.first == dl.second) ldis = INF;   //判重
        else ldis = dist(p[dl.first],p[dl.second]);
    
        if(dr.first == dr.second) rdis = INF;
        else rdis = dist(p[dr.first],p[dr.second]);
    
        pair<int,int> ans = ldis < rdis ? dl : dr ; //左右两部分的最值点对
        ans_dis = min(ldis,rdis);                   //左右两部分的最值
    
        // 从中向左右两边找在[p[m].x-d,p[m].x+d]的平面内所有点
        // 这以后的复杂度就不太好估计了...
        // 这段模板是用暴力找的...我只做了一点点优化...
        int cnt = 0;
        for(int i = m ; i >= l ; i--){
            double q = sqrt((double)(p[m].x - p[i].x) * (p[m].x - p[i].x));
            if(p[i].x < p[m].x - q) break;
            if(q <= ans_dis){
                tmp[cnt++] = p[i];
            }
        }
        for(int i = m+1 ; i <= r ; i++){
            double q = sqrt((double)(p[m].x - p[i].x) * (p[m].x - p[i].x));
            if(p[i].x > p[m].x + q) break;
            if(q <= ans_dis){
                tmp[cnt++] = p[i];
            }
        }
        //按y方向进行筛选 ,相隔大于d的点可以直接跳过
        sort(tmp,tmp+cnt,cmp1);
        for(int i = 0 ; i < cnt ; i++){
            for(int j = i+1 ; j < cnt ; j++){
                if(sqrt((double)(tmp[i].y - tmp[j].y) * (tmp[i].y - tmp[j].y)) >= ans_dis)
                   break;
                if(dist(tmp[i],tmp[j]) < ans_dis){
                    ans_dis = dist(tmp[i],tmp[j]);
                    ans = make_pair(tmp[i].pos,tmp[j].pos);
                }
            }
        }
        return ans;
    }
    int main()
    {
        //FIN;
        while(cin>>n && n){
            for(int i = 0 ; i < n ; i++)
                scanf("%lf%lf",&p[i].x,&p[i].y);
            sort(p,p+n,cmp);
            for(int i = 0 ; i < n ; i++)
                p[i].pos = i;
            pair<int,int> ans = Closest_Pair(0,n-1);
            double res = dist(p[ans.first],p[ans.second]);
            printf("%.2lf
    ",res/2);
        }
        return 0;
    }
  • 相关阅读:
    Day 20 初识面向对象
    Day 16 常用模块
    Day 15 正则表达式 re模块
    D14 模块 导入模块 开发目录规范
    Day 13 迭代器,生成器,内置函数
    Day 12 递归,二分算法,推导式,匿名函数
    Day 11 闭包函数.装饰器
    D10 函数(二) 嵌套,命名空间作用域
    D09 函数(一) 返回值,参数
    Day 07 Day08 字符编码与文件处理
  • 原文地址:https://www.cnblogs.com/Felix-F/p/3228738.html
Copyright © 2011-2022 走看看