平面最近点对问题

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cmath>
  4. using   namespace  std;
  5.  
  6. /*      存储点的结构    */
  7. typedef   struct {
  8.           float  x,y;        //    点的x,y坐标
  9. }POINT;
  10.  
  11. /* 辅助的点结构 */
  12. typedef   struct {
  13.           int  index;        //    点在X数组中的下标
  14.           float  x, y;      //   点的x,y坐标
  15. }A_POINT;
  16.  
  17. /* 对点进行递增顺序排序的比较 */
  18. bool  compareX (POINT a, POINT b ) {
  19.           return  b. x>a. x;
  20. }
  21.  
  22. /* 对辅助点进行递增排序的比较 */
  23. bool  compareY (A_POINT a, A_POINT b ) {
  24.           return  b. y>a. y;
  25. }
  26.  
  27. /* 计算两点距离的平方 */
  28. float  dist (POINT a, POINT b ) {
  29.           float  dx, dy;
  30.         dx = a. x  - b. x, dy = a. y  - b. y;
  31.           return   (dx*dx+dy*dy );
  32. }
  33.  
  34. /************************************************************************
  35. * 求平面点集最近点对的分治算法
  36. *
  37. * 输入:存放平面点集点的数组X[]、辅助点数组Y[],数组起点下标low与终点下标high
  38. * 输出:最近点对a,b及距离d
  39. **********************************************************************/
  40. void  closest (POINT X [ ], A_POINT Y [ ],   int  low,   int  high, POINT &a, POINT &b,   float  &d ) {
  41.           int  i,j,k,m;
  42.         POINT al,bl,ar,br;
  43.           float  dl,dr;
  44.           if ( (high-low )== 1 ) {              //    当n=2时直接计算
  45.                 a = X [low ], b = X [high ], d = dist (X [low ], X [high ] );
  46.           } else {
  47.                   if ( (high-low )== 2 ) {        //    当n=3时直接计算
  48.                         dl = dist (X [low ], X [low +1 ] );
  49.                         dr = dist (X [low ], X [low +2 ] );
  50.                         d = dist (X [low +1 ], X [low +2 ] );
  51.                           if ( (dl<=dr )&& (dl<=d ) ) {
  52.                                 a = X [low ], b = X [low +1 ], d = dl;
  53.                           } else {
  54.                                   if (dr<=d ) {
  55.                                         a = X [low ], b = X [low +2 ], d= dr;
  56.                                   } else {
  57.                                         a = X [low +1 ], b = X [low +2 ];
  58.                                   }
  59.                           }
  60.                   } else {          //        当n>3时进行分治
  61.                         A_POINT *SL =   new  A_POINT [ (high-low )/ 2 +1 ];
  62.                         A_POINT *SR =   new  A_POINT [ (high-low )/ 2 ];
  63.  
  64.                         m =   (high-low )/ 2  + low;     //       把x数组以m为界划分为两半
  65.                         j = k =   0;
  66.                           for (i= 0; i<=high-low; i++ ) {     
  67.                                   if (Y [i ]. index<=m ) {
  68.                                         SL [j++ ]  = Y [i ];    //       收集左边子集中的最近点对
  69.                                   } else {
  70.                                         SR [k++ ]  = Y [i ];    //       收集右边子集中的最近点对
  71.                                   }
  72.                           }
  73.  
  74.                         closest (X,SL,low, m, al, bl, dl );        //     计算左边子集的最近点对
  75.                         closest (X,SR,m +1, high, ar, br, dr ); //  计算右边子集的最近点对
  76.  
  77.                           if (dl<dr ) {                                //    组合步得到左右子集中点的最短距离d
  78.                                 a = al, b = bl, d = dl;
  79.                           } else {
  80.                                 a = ar, b = br, d = dr;
  81.                           }
  82.  
  83.                         POINT *Z =   new  POINT [high-low +1 ];
  84.                         k =   0;
  85.                           for (  i= 0; i<=high -low; i++ ) {       // 收集距离中线距离小于d的元素,保存到数组Z(因Y数组按y坐标递增排序,Z数组也一样)
  86.                                   if ( fabs (X [m ]. x  - Y [i ]. x )<d ) {
  87.                                         Z [k ]. x  = Y [i ]. x, Z [k++ ]. y  = Y [i ]. y;
  88.                                   }
  89.                           }
  90.                           for (  i= 0; i<k; i++ ) {
  91.                                   for (  j=i +1;   (j<k )&& (Z [j ]. y-Z [i ]. y<d ); j++ ) {      //   若前后两点y轴的距离超过d则不可能使距离小于d,退出
  92.                                         dl = dist (Z [i ], Z [j ] );    //        计算前后两点的距离
  93.                                           if (dl<d ) {                                    //     若小于d,则更新
  94.                                                 a = Z [i ], b = Z [j ], d = dl;
  95.                                           }
  96.                                   }
  97.                           }
  98.  
  99.                           delete  SL;
  100.                           delete  SR;
  101.                           delete  Z;
  102.                   }
  103.           }
  104. }
  105.  
  106. /**********************************************
  107. * 求平面点集最近点对的分治算法
  108. *
  109. * 输入:存放平面点集点的数组X[],点的个数n
  110. * 输出:最近点对a,b及距离d
  111. **********************************************/
  112. void  closest_pair (POINT X [ ],   int  n, POINT &a, POINT &b,   float  &d ) {
  113.           if (n< 2 ) {          //      当点集个数小于2时不存在最近点对
  114.                 d =   0;
  115.           } else {
  116.                 sort (X,X+n, compareX );        //        对x数组进行递增排序
  117.                 A_POINT *Y =   new  A_POINT [n ];      //  初始化辅助点数组Y
  118.                   for (   int  i =   0  ; i < n ;i ++ ) {
  119.                         Y [i ]. index  = i;
  120.                         Y [i ]. x  = X [i ]. x;
  121.                         Y [i ]. y  = X [i ]. y;
  122.                   }
  123.                 sort (Y,Y+n, compareY );        //        对y数组进行递增排序
  124.                 closest (X,Y, 0,n -1,a,b,d );               //     求亲密点对
  125.                 d =   sqrt (d );                  //  将得到的d开平方才是两点间真正的距离
  126.                   delete  Y;
  127.           }
  128. }
  129.  
  130. int  main ( ) {
  131.           int  n;
  132.  
  133.         cout<< "请输入点个数:";
  134.         cin>>n;
  135.  
  136.         cout<< "请输入各个点的坐标:"<<endl;
  137.         POINT *X =   new  POINT [n ];
  138.           for ( int  i= 0; i<n; i++ ) {
  139.                 cin>>X [i ]. x>>X [i ]. y;
  140.           }
  141.  
  142.         POINT a,b;
  143.           float  d;
  144.         closest_pair (X,n,a,b,d );
  145.        
  146.           if (n>= 2 ) {
  147.                   printf ( "(%.2f,%.2f) - (%.2f,%.2f) : %.2f\n", a. x, a. y, b. x, b. y, d );
  148.           } else {
  149.                   printf ( "不存在最近点对!\n" );
  150.           }
  151.        
  152.           delete  X;
  153.           return   0;
  154. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值