• 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;
    }
  • 相关阅读:
    C#结构体指针的定义及使用详解
    C# out和ref关键字
    CListCtrl控件主要事件及LVN_ITEMCHANGED消息和鼠标双击列表项事件的处理
    深圳职位:替朋友招聘biztalk的技术人员 无为而为
    微软出最新SQL Server 2005 累积修补程序包(版本 9.0.2153)(200684),这是SP1之后的更新 无为而为
    微软Visual Studio 2005 SDK version 3.0 发布了,TFS扩展的开发人员/DSL/VSTS Test都应该关注 无为而为
    好东西,将你的英文版TFS变为中文版?:Visual Studio 2005 Team Foundation Server 语言更改包 无为而为
    Analysis Service计算[期间增长率]的若干注意 无为而为
    亲身体验:更改 Team Foundation Server 部署的语言版本是一个复杂耗时的过程 无为而为
    各大门户调查:鄙视新浪,将博士伦的广告挂在热点新闻中间好几天了,把大众当傻瓜 无为而为
  • 原文地址:https://www.cnblogs.com/Felix-F/p/3228738.html
Copyright © 2020-2023  润新知