hdu 1007 分治

题意:求最近点对

暴力一定超时,分治:(代码参考别人)

求最大的环,此环只能套中一个,所以只能先找出距离最小的两点且其距离就是环的直径,不然该环就有可能一次套中两个环。所以这题的题意是:求最近点对。

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<math.h>
#include<algorithm>
#define DX(x) ((x)*(x))
using namespace std;
const int MAX=100000+1;
int n;
struct Point
{
    double x,y;
    int index;
}a[MAX],b[MAX],c[MAX];
double getdis(Point a,Point b)
{
       return sqrt(DX(a.x-b.x)+DX(a.y-b.y));
}
/*double getmin(double a,double b)
{
       if(a<b) return a;
       else return b;
}*/
inline double getmin(double a, double b)
 {
     return a < b ? a : b;
 }
bool cmpx(const Point& a,const Point& b)
{
     if(a.x==b.x) return a.y<b.y;
     return a.x<b.x;
}
bool cmpy(const Point& a,const Point& b)
{
     if(a.y==b.y) return a.x<b.x;
     return a.y<b.y;
}
void merget(Point b[],Point c[],int p,int m,int q)   //合并 
{
     int i,j,k;
     for(i=p,k=p,j=m+1;i<=m&&j<=q;)   //两边都是按y从小到大排列,所以只用比较
                                      //两边的最左方的y值,即可得总的y的升序排列 
     {
          if(c[i].y>c[k].y)  b[k++]=c[i], j++;
          else  b[k++]=c[i],i++;
     }
     while(i<=m)  b[k++]=c[i++];
     while(j<=q)  b[k++]=c[j++];
}
double closet(Point a[],Point b[],Point c[],int p,int q)
{
       double d1,d2;
       if(q - p == 1) return getdis(a[p],a[q]);
       if(q - p == 2)
       {
            double x1=getdis(a[p],a[p+1]);
            double x2=getdis(a[p],a[q]);
            double x3=getdis(a[p+1],a[q]);
            return getmin(x1,getmin(x2,x3));
       }
       
           int m=(q + p)/2,i,j,k;
           //为了正确 的分治、
           for(i = p,j = p,k = m + 1; i <=q; ++i)
           {
                if(b[i].index<=m) c[j++]=b[i];
                else c[k++]=b[i];
           } 
           d1=closet(a,c,b,p,m);
           d2=closet(a,c,b,m+1,q);
           merget(b,c,p,m,q);
           double dm=getmin(d1,d2);
           for(i = p, k = p;i <= q;++i)
           {
               if(fabs(b[i].x-b[m].x) < dm)
                    c[k++]=b[i];
           }
           for(i = p; i < k; ++i)
           {
                 for(j = i + 1; j < k && c[j].y - c[i].y < dm; ++j)
                 {
                      double temp=getdis(c[i],c[j]);
                      if(temp < dm) dm=temp;
                 } 
           }
           return dm;
}
int main()
{
    
    while(scanf("%d",&n)!=EOF&&n!=0)
    {
         for(int i=0;i<n;i++)   
         {scanf("%lf%lf",&a[i].x,&a[i].y); }
         sort(a,a+n,cmpx);
         for(int i=0;i<n;i++)  a[i].index=i;
         memcpy(b,a,n*sizeof(b[0]));
         sort(b,b+n,cmpy);
         double dis=closet(a,b,c,0,n-1);
         printf("%.2lf\n",dis/2.0);
         }
    return 0;
}



注1:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值