最远点对问题[转]

最远点对问题[转]
最远点对问题

    类似于“最近点对问题”,这个问题也可以用枚举的方法求解,时间复杂度O(n^2)。假设平面上有n个点,那么这一对最远点必然存在于这n个点所构成的一 个凸包上,为了降低时间复杂度,可以先将这n个点按极角排序,然后利用Graham_scan法求出这个凸包,再枚举凸包上的所有顶点(也可以用旋转卡 壳)求出这个最远距离,时间复杂度O(nlogn)。再最坏的情况下,如果这n个点本身就构成了一个凸包,时间复杂度为O(n^2)。该算法的平均复杂度 为O(nlogn)。
#include  < cstdio >
#include 
< cstring >
#include 
< cmath >
#include 
< cstdlib >

const   int  MAXN  =   100001 ;
const   double  eps  =  1e - 6 ;
struct  point{
    
double  x,y;
}p[MAXN],h[MAXN];

inline 
double  distance( const  point  & p1, const  point  & p2){
    
return  sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
}
inline 
double  multiply( const  point  & sp, const  point  & ep, const  point  & op){
      
return  ((sp.x - op.x) * (ep.y - op.y) - (ep.x - op.x) * (sp.y - op.y));
}
int  cmp( const   void   * a, const   void   * b){
    point 
* p1  =  (point  * )a;
    point 
* p2  =  (point  * )b;
    
double  t  =  (p1 -> y - p[ 0 ].y) * (p2 -> x - p[ 0 ].x) - (p2 -> y - p[ 0 ].y) * (p1 -> x - p[ 0 ].x);
    
if (t > eps)  return   1 ;
    
else   if (fabs(t) <= eps)  return   0 ;
    
else   return   - 1 ;
}
void  anglesort(point p[], int  n){
    
int  i,k = 0 ;
    point temp;
    
for (i = 1 ;i < n;i ++ )
        
if (p[i].x < p[k].x  ||  (p[i].x == p[k].x)  &&  (p[i].y < p[k].y))
            k
= i;
    temp
= p[ 0 ],p[ 0 ] = p[k],p[k] = temp;
    qsort(p
+ 1 ,n - 1 , sizeof (point),cmp);
}
void  Graham_scan(point p[],point ch[], int  n, int   & len){
    
int  i,top = 2 ;
    anglesort(p,n);
    
if (n < 3 ){
        
for (i = 0 ,len = n;i < n;i ++ ) ch[i] = p[i];
        
return ;
    }
    ch[
0 ] = p[ 0 ],ch[ 1 ] = p[ 1 ],ch[ 2 ] = p[ 2 ];
    
for (i = 3 ;i < n;i ++ ){
        
while (multiply(p[i],ch[top],ch[top - 1 ]) >= 0 ) top -- ;
        ch[
++ top] = p[i];
    }
    len
= top + 1 ;
}
int  main(){
    
int  i,j,n,len;
    
double  d,ans;
    
while (scanf( " %d " , & n),n){
        
for (i = 0 ;i < n;i ++ ) scanf( " %lf %lf " , & p[i].x, & p[i].y);
        Graham_scan(p,h,n,len);
        
for (ans = i = 0 ;i < len;i ++ )
            
for (j = i + 1 ;j < len;j ++ ){
                d
= distance(h[i],h[j]);
                
if (d > ans) ans = d;
            }
        printf(
" %.2lf\n " ,ans);
    }
    
return   0 ;
}


接下来所谓旋转卡壳法(类似求数组中最长子段的和):
int  main(){
    
while ( ~ scanf( " %d " & n))    {
        
for ( int  i  =   0 ; i  <  n; i  ++ )
            p[i].read();
        
int  top  =   0 ;
        tubao(p, id, n, top);
        
int  area, area2, i, j, k, t, maxx  =   0 ;
        
for (i  =   0 , k  =   2 ; i  <  top; i  ++ ){
            j 
=  (i  +   1 %  top;
            t 
=  (k  +   1 %  top;
            area 
= fabs(xmul(p[id[i]], p[id[k]], p[id[j]]));
            area2 
= fabs(xmul(p[id[i]], p[id[t]], p[id[j]]));
            
while (area  <  area2){    
                area 
=  area2;
                k 
=  (k  +   1 %  top;
                t 
=  (k  +   1 %  top;
                area2 
= fabs(xmul(p[id[i]], p[id[t]], p[id[j]]));
                maxx 
=  max(maxx, max( dist(p[id[i]], p[id[k]]), dist(p[id[i]], p[id[t]]) ));
            }
        }
        
if (maxx  !=   0 )
            printf(
" %lf\n " , maxx);
        
else
            printf(
" %lf\n " , dist(p[id[ 0 ]], p[id[top - 1 ]]));

    }

}

你可能感兴趣的:(最远点对问题[转])