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\n",sqrt(ans)/2.0);
75     }
76     //clock_t ed=clock();
77     //printf("\n\nTime Used : %.5lf Ms.\n",(double)(ed-st)/CLOCKS_PER_SEC);
78     return 0;
79 }

 

posted @ 2017-04-07 10:51  CtrlKismet  阅读(703)  评论(0编辑  收藏  举报