zoukankan      html  css  js  c++  java
  • HDOJ1007解题报告【二分思维题】

    题目地址:

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

    题目概述:

      给出n个点,求n个点两两之间的最小距离。

    大致思路:

      直接暴力的话复杂度是O(n²),这个复杂度在n=100000的时候是无法承受的,那么我们就需要降低复杂度了。

      对平面内任一铅垂线来说,这个最小距离要么在这条线左,要么在这条线右,要么跨过这条线,这个时候想到了什么?二分!

      考虑用二分来解决这个题目,铅垂线直接找最中间的点的x坐标即可,这样可以保证二分的复杂度在O(logn),这样的话就只需要解决跨过铅垂线的情况了。

      假设左边和右边的最小距离的较小值为d,那么实际上跨过铅垂线又是最小距离的点对他们的x坐标与铅垂线的水平距离一定不会超过d,看上去只需要枚举所有水平距离小于d的点对就好了,不过如果对一个 半区间 来说,它里面的所有点都聚集在距离小于d的地方怎么办?这个时候按上述思路枚举显然复杂度会退化到O(n²)。

      其实看懂上面枚举水平距离的做法这个问题就很好解决了,因为显然垂直距离也满足这个条件。所以枚举是只需要枚举水平,垂直距离均小于d的点对即可。

      注意先对所有点按x,y升序排列。

    复杂度分析:

      理论上来说二分复杂度是O(nlogn),所以复杂度应该取决于解决跨过铅垂线时枚举的点对的数目,只要出题人不刻意卡数据的话,可以大致认为复杂度为O(nlogn)。

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstdlib>
     4 #include <cmath>
     5 #include <vector>
     6 #include <ctime>
     7 #include <map>
     8 #include <stack>
     9 #include <queue>
    10 #include <cstring>
    11 #include <algorithm>
    12 using namespace std;
    13 
    14 #define sacnf scanf
    15 #define scnaf scanf
    16 #define maxn  100010
    17 #define maxm 26
    18 #define inf 1061109567
    19 #define Eps 0.00001
    20 const double PI=acos(-1.0);
    21 #define mod 1000033
    22 #define MAXNUM 10000
    23 void Swap(int &a,int &b) {int t=a;a=b;b=t;}
    24 int Abs(int x) {return (x<0)?-x:x;}
    25 typedef long long ll;
    26 typedef unsigned int uint;
    27 
    28 struct node
    29 {
    30     double x,y;
    31     bool operator < (const node &a) const
    32     {
    33         if(x==a.x) return y<a.y;
    34         else return x<a.x;
    35     }
    36 } a[maxn];
    37 
    38 double dist(node a,node b) {return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);}
    39 
    40 double query(int l,int r)
    41 {
    42     if(l+1==r) return dist(a[l],a[r]);
    43     if(l==r) return inf;
    44     int m=(l+r)>>1;
    45     double d1=query(l,m);
    46     double d2=query(m+1,r);
    47     double d=min(d1,d2);
    48     for(int i=m;i>=l&&a[m].x-a[i].x<=d;i--)
    49     {
    50         for(int j=m+1;j<=r&&a[j].x-a[m].x<=d;j++)
    51         {
    52             if(a[j].y>a[m].y+d) break;
    53             d=min(d,dist(a[i],a[j]));
    54         }
    55     }
    56     return d;
    57 }
    58 
    59 int main()
    60 {
    61     freopen("data.in","r",stdin);
    62     //freopen("data.out","w",stdout);
    63     //clock_t st=clock();
    64     int n;
    65     while(~scanf("%d",&n))
    66     {
    67         if(n==0) break;
    68         for(int i=1;i<=n;i++)
    69         {
    70             sacnf("%lf%lf",&a[i].x,&a[i].y);
    71         }
    72         sort(a+1,a+1+n);
    73         double ans=query(1,n);
    74         printf("%.2lf
    ",sqrt(ans)/2.0);
    75     }
    76     //clock_t ed=clock();
    77     //printf("
    
    Time Used : %.5lf Ms.
    ",(double)(ed-st)/CLOCKS_PER_SEC);
    78     return 0;
    79 }
  • 相关阅读:
    云原生范式转变:您准备好了吗?
    CentOS 6.x 开机 自启动 脚本
    忠告 程序员 先思考再编程,累的时候不要写代码
    服务化架构组件清单
    代码自动修复
    选择塑造人生
    mariadb change password
    Spring 集成 Druid Monitor URL 配置转义问题(xml or properties)
    挣钱 vs. 花钱
    管理的要义
  • 原文地址:https://www.cnblogs.com/CtrlKismet/p/6677066.html
Copyright © 2011-2022 走看看