http://acm.hdu.edu.cn/showproblem.php?pid=1007
题意:
给出二维平面上的n个点,求其中最近的两个点距离的一般一半。
输入包含多组数据。每组数据第一行为n,表示点的个数;接下来n行,每行为一个点的坐标。当n为0时表示输入结束。每组数据输出一行,为最近的两个点的距离的一半。
思路:
首先暴力枚举肯定不行,数据范围1e5,
采用分治法,
1,把n个点按x坐标进行排序,
2,选取一个中点mid,将所有点分成两个部分(L,mid)和(mid+1,R)
有三种情况:
两个点都在左边
两个点都在右边
一个在左边,一个在右边
3,一二种结果很容易就可以求出得到Lmin和Rmin d=min(Lmin,Rmin);
对于第三种情况,在以mid为中心,宽为2d的带状区域,选取此区域内的所有点,按照y轴进行排序,一一枚举这些点,更新最小距离即可。
还可进一步剪枝,如果当前点到达基点的距离已经大于d,那么就可以更换下一个基点。
PS:对于左边的任意一点,右边的点一定落在一个d*2d的矩形中,且最多只需检查6个点(鸽巣原理),按照y轴排序后,进行线性扫描,此时合并的时间复杂度为O(n*logn),几乎为线性了。
HDU卡cin,记得用scanf。
代码:
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<string> #include<iomanip> #include<algorithm> #include<string.h> #include<queue> #include<cmath> using namespace std; const int maxn=1e5+10; const int inf=1e10; typedef long long ll; struct node {double x,y;}; bool cmpx(node a,node b){return a.x<b.x;} bool cmpy(node a,node b){return a.y<b.y;} double Dis(node a,node b){return sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2));} node a[maxn],b[maxn]; double cal(int s,int e) { if(s==e) return inf; int mid=(s+e)/2; double d=min(cal(s,mid),cal(mid+1,e)); int num=0; for(int i=mid; i>=s&&(a[mid].x-a[i].x)<d; i--) b[num++]=a[i]; for(int i=mid+1; i<=e&&(a[i].x-a[mid].y)<d; i++) b[num++]=a[i]; sort(b,b+num,cmpy); for(int i=0; i<num; i++) { for(int j=i+1; j<num&&b[j].y-b[i].y<d; j++) { if(Dis(b[i],b[j])<d) d=Dis(b[i],b[j]); } } return d; } int main() { int n; while(cin>>n&&n) { for(int i=0; i<n; i++) scanf("%lf%lf",&a[i].x,&a[i].y); sort(a,a+n,cmpx); double ans=cal(0,n-1); printf("%.2lf ",ans/2.0); } system("pause"); return 0; }