编程之美--2.11 寻找最近点对

[cpp]  view plain copy
  1. /* 
  2. 对于这类题目,首先要对进行划分区域,要划分区域就要按照X坐标进行排序,然后进行划分,当划分到只有两个点或者三个点时,在进行求点之间的距离,并记录! 
  3. 接下来进来区域之间的合并,当当前的点到刚才以这个划分区域为准的中线距离大于刚才我们所求的距离时,则放弃,否则进行更新最短距离! 
  4. 总体算法思想就是利用递归最后进行合并的思想! 
  5. */  
  6. #include<iostream>  
  7. #include<cmath>  
  8. #include<algorithm>  
  9. #define eps 1e-10  
  10. using namespace std;  
  11. //最近点对问题  
  12. const int maxn=200001;  
  13. const double INF=1e100;  
  14. typedef struct point  
  15. {  
  16.     double x,y;  
  17.     int flag;  
  18.     point(){};  
  19.     point(double xx,double yy){x=xx;y=yy;}      
  20. }point;  
  21. point p[maxn];  
  22. int n;   
  23. int com(double x,double y)  
  24. {  
  25.     if(x==y)  
  26.         return 0;  
  27.     if(x>y)  
  28.         return 1;  
  29.     return -1;   
  30. }   
  31. double min(double a, double b)  
  32. {  
  33.     return a<b?a:b;  
  34. }  
  35. bool cmp1(point a,point b)//对于x进行排序  
  36. {  
  37.     return com(a.x,b.x)<0;  
  38. }  
  39. bool cmp2(int a,int b)//对于y进行排序  
  40. {  
  41.     return com(p[a].y,p[b].y)<0;  
  42. }  
  43. double dist(point &a,point &b)//传入两个点,求两点距离   
  44. {  
  45.     return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));  
  46. }  
  47. int b[maxn], k;   
  48. double min_dis(point p[],int left,int right)//求从left到right这些点p[i]的最近点对   
  49. {  
  50.     int mid=(left+right)>>1,i,j;  
  51.     double ret=INF;  
  52.     if(left>=right)  
  53.         return ret;  
  54.     for(i=mid; i>=left && !com(p[i].x,p[mid].x); i--);//取中间的点  
  55.     ret=min_dis(p,left,i);  
  56.     for(i=mid; i<=right && !com(p[i].x,p[mid].x); i++);  
  57.     ret=min(ret,min_dis(p,i,right));  
  58.     k = 0;//寻找那些到我们所参考的点比ret小的点的个数  
  59.     for(i=mid; i>=left && com(p[mid].x-p[i].x,ret)<=0; i--)  
  60.         b[++k]=i;  
  61.     for(i=mid+1; i<=right && com(p[i].x-p[mid].x,ret)<=0; i++)  
  62.         b[++k]=i;  
  63.     sort(b+1,b+k+1,cmp2);  
  64.     for(i=1; i<=k; i++)  
  65.         for(j=1; j+i<=k; j++)  
  66.             if(i+j<=k && com(p[b[i+j]].y-p[b[i]].y,ret) < 0 && p[b[i]].flag != p[b[i+j]].flag)  
  67.                 ret=min(ret,dist(p[b[i]],p[b[i+j]]));   
  68.     return ret;   
  69. }   
  70. int main()  
  71. {  
  72.   //  freopen("in.txt","r",stdin);  
  73.     int i,j,k,test;  
  74.     scanf("%d",&test);  
  75.     while(test--)  
  76.     {  
  77.         scanf("%d",&n);  
  78.         for(i=1;i<=n;i++)  
  79.         {  
  80.             scanf("%lf%lf",&p[i].x,&p[i].y);  
  81.             p[i].flag=1;  
  82.         }  
  83.         for(i=1; i<=n; i++)  
  84.         {  
  85.             scanf("%lf %lf", &p[i+n].x, &p[i+n].y);  
  86.             p[i+n].flag = 2;  
  87.         }  
  88.         n<<=1;  
  89.         sort(p+1,p+n+1,cmp1);  
  90.         printf("%.3lf/n",min_dis(p,1,n));      
  91.     }  
  92.     return 0;  
  93. }  
对于这类题目,首先要对进行划分区域,要划分区域就要按照X坐标进行排序,然后进行划分,当划分到只有两个点或者三个点时,在进行求点之间的距离,并记录!

接下来进来区域之间的合并,当当前的点到刚才以这个划分区域为准的中线距离大于刚才我们所求的距离时,则放弃,否则进行更新最短距离!

总体算法思想就是利用递归最后进行合并的思想!

算法模版如下:

[cpp]  view plain copy
  1. /* 
  2. 对于这类题目,首先要对进行划分区域,要划分区域就要按照X坐标进行排序,然后进行划分,当划分到只有两个点或者三个点时,在进行求点之间的距离,并记录! 
  3. 接下来进来区域之间的合并,当当前的点到刚才以这个划分区域为准的中线距离大于刚才我们所求的距离时,则放弃,否则进行更新最短距离! 
  4. 总体算法思想就是利用递归最后进行合并的思想! 
  5. */  
  6. #include<iostream>  
  7. #include<cmath>  
  8. #include<algorithm>  
  9. #define eps 1e-10  
  10. using namespace std;  
  11. //最近点对问题  
  12. const int maxn=200001;  
  13. const double INF=1e100;  
  14. typedef struct point  
  15. {  
  16.     double x,y;  
  17.     point(){};  
  18.     point(double xx,double yy){x=xx;y=yy;}      
  19. }point;  
  20. point p[maxn];  
  21. int n;   
  22. int com(double x,double y)  
  23. {  
  24.     if(x==y)  
  25.         return 0;  
  26.     if(x>y)  
  27.         return 1;  
  28.     return -1;   
  29. }   
  30. double min(double a, double b)  
  31. {  
  32.     return a<b?a:b;  
  33. }  
  34. bool cmp1(point a,point b)//对于x进行排序  
  35. {  
  36.     return com(a.x,b.x)<0;  
  37. }  
  38. bool cmp2(int a,int b)//对于y进行排序  
  39. {  
  40.     return com(p[a].y,p[b].y)<0;  
  41. }  
  42. double dist(point &a,point &b)//传入两个点,求两点距离   
  43. {  
  44.     return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));  
  45. }  
  46. int b[maxn], k;   
  47. double min_dis(point p[],int left,int right)//求从left到right这些点p[i]的最近点对   
  48. {  
  49.     int mid=(left+right)>>1,i,j;  
  50.     double ret=INF;  
  51.     if(left>=right)  
  52.         return ret;  
  53.     for(i=mid; i>=left && !com(p[i].x,p[mid].x); i--);//取中间的点  
  54.     ret=min_dis(p,left,i);  
  55.     for(i=mid; i<=right && !com(p[i].x,p[mid].x); i++);  
  56.     ret=min(ret,min_dis(p,i,right));  
  57.     k = 0;//寻找那些到我们所参考的点比ret小的点的个数  
  58.     for(i=mid; i>=left && com(p[mid].x-p[i].x,ret)<=0; i--)  
  59.         b[++k]=i;  
  60.     for(i=mid+1; i<=right && com(p[i].x-p[mid].x,ret)<=0; i++)  
  61.         b[++k]=i;  
  62.     sort(b+1,b+k+1,cmp2);  
  63.     for(i=1; i<=k; i++)  
  64.         for(j=1; j+i<=k; j++)  
  65.             if(i+j<=k && com(p[b[i+j]].y-p[b[i]].y,ret) < 0)  
  66.                 ret=min(ret,dist(p[b[i]],p[b[i+j]]));   
  67.     return ret;   
  68. }   
  69. int main()  
  70. {  
  71.     freopen("in.txt","r",stdin);  
  72.     int i,j,k,test;  
  73.     scanf("%d",&test);  
  74.     while(test--)  
  75.     {  
  76.         scanf("%d",&n);  
  77.         for(i=1;i<=n;i++)  
  78.         {  
  79.             scanf("%lf%lf",&p[i].x,&p[i].y);  
  80.         //  p[i].flag=1;  
  81.         }      
  82.         sort(p+1,p+n+1,cmp1);  
  83.         printf("%.3lf/n",min_dis(p,1,n));      
  84.     }  
  85.     return 0;  
  86. }  
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值