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 }