hdu 1007 最近点对 模板

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1007

本类题的做法思想就是不断的二分,直到剩余两个点或者三个点时直接算。这里存在的一个问题就是可能最近的点对不在二分的左右区间里,而是跨越两个区间,所以我们在做时刚开始时,对x轴由小到大排序,然后二分,在二分之后已经得到一个最小值ans,把在中心线左右ans内的点选出来,把这个区间的点按y坐标由小到大排序,由于这些点的个数有限,所以可以直接求,这里还可以有个优化,如果y方向上的差值大于ans的话 就可以break原因是y坐标是有序的从小到大。

View Code
 1 #include<cmath>
2 #include<cstdio>
3 #include<iostream>
4 #include<algorithm>
5 using namespace std;
6 #define N 100005
7 struct point
8 {
9 double x;
10 double y;
11 }p1[N],p2[N];
12 bool cmpx(point a,point b)//按x坐标排序
13 {
14 return a.x<b.x;
15 }
16 bool cmpy(point a,point b)//按y坐标排序
17 {
18 return a.y<b.y;
19 }
20 double dis(point a,point b)//求两点的距离
21 {
22 return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
23 }
24 double min(double a,double b)//取最小值
25 {
26 return a>b?b:a;
27 }
28 double mindis(int l,int r)//求最近点对
29 {
30 int i,j;
31 if(l+1==r)return dis(p1[l],p1[r]);//如果就两个点
32 if(l+2==r)return min(dis(p1[l],p1[l+1]),min(dis(p1[l],p1[r]),dis(p1[l+1],p1[r])));//就三个点的情况
33 int mid=(l+r)>>1;
34 double ans=min(mindis(l,mid),mindis(mid+1,r)); //取两边(左边或者右边)的最小值
35
36 int cn=0;
37 for(i=l;i<=r;i++)//选出在分界线(左右)ans内的点
38 {
39 if(p1[i].x>=p1[mid].x-ans&&p1[i].x<=p1[mid].x+ans)
40 p2[cn++]=p1[i];
41
42 }
43
44 sort(p2,p2+cn,cmpy);//把区域内的点按y坐标排序。
45 for(i=0;i<cn;i++)
46 {
47 for(j=i+1;j<cn;j++)
48 {
49 if(p2[j].y-p2[i].y>=ans)break;//优化 大于的肯定不会是解
50 ans=min(ans,dis(p2[i],p2[j]));
51 }
52 }
53 return ans;
54 }
55 int main()
56 {
57 int n;
58 while(scanf("%d",&n)&&n)
59 {
60 for(int i=0;i<n;i++)
61 scanf("%lf%lf",&p1[i].x,&p1[i].y);
62 sort(p1,p1+n,cmpx);//按x坐标排序
63
64 double dist=mindis(0,n-1);
65
66 printf("%.2lf\n",dist/2);
67 }
68 return 0;
69 }



posted @ 2012-03-23 17:43  我们一直在努力  阅读(347)  评论(1编辑  收藏  举报