poj 2187 Beauty Contest(凸包+旋转卡壳)

通过这题有学习了关于求凸多边形的直径的方法,真的很巧妙~

旋转卡壳可以用于求凸包的直径、宽度,两个不相交凸包间的最大距离和最小距离等,参考了下面的两个博客,原理基本上明白了。留下链接,以便后面复习用~

http://www.cnblogs.com/Booble/archive/2011/04/03/2004865.html

 

http://www.cppblog.com/staryjy/archive/2009/11/19/101412.html

 

其实这题完全可以不用旋转卡壳,可能是后台数据量很小,直接用暴力求解也可以过,而且时间和用了旋转卡壳的时间相差无几。

不用旋转卡壳(125ms)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#include <string>
#define N 50005
using namespace std ;

struct node
{
    int x ;
    int y ;
}p[N] , q[N] ;

int n , top ;

int dis ( struct node a , struct node b )
{
    return (( a.x - b.x ) * ( a.x - b.x ) + ( a.y - b.y ) * ( a.y - b.y ));
}

double cross ( struct node p1 , struct node p2 , struct node p0 )
{
    return (( p1.x -p0.x ) * ( p2.y - p0.y ) - ( p2.x - p0.x ) * ( p1.y - p0.y ));
}

int cmp ( struct node p1 , struct node p2 )
{
    if ( cross ( p1 , p2 , p[0] ) > 0 )
    return 1 ;
    if ( cross ( p1 , p2 , p[0] ) == 0 && dis( p1 , p[0] ) < dis( p2 , p[0] ))
    return 1 ;
    return 0 ;
}

void Graham ()
{
    int i , j , k ;
    k = 0 ;
    for ( i = 1 ; i < n ; i++ )
    if ( (p[i].y < p[k].y ) || ( p[i].y == p[k].y && p[i].x < p[k].x ))
    k = i ;

    struct node tem = p[k] ;
    p[k] = p[0] ;
    p[0] = tem ;

    sort ( p , p + n , cmp );

    top = 0 ;
    q[top++] = p[0] ;
    q[top++] = p[1] ;
    q[top++] = p[2] ;
    for ( i = 3 ; i < n ; i++ )
    {
        while ( cross ( p[i] , q[top-1] , q[top-2] ) >= 0 )
        top-- ;
        q[top++] = p[i] ;
    }
}

int main()
{
    int i , j ;

    scanf ( "%d" , &n ) ;
    for ( i = 0 ; i < n ; i++ )
    scanf ( "%d%d" , &p[i].x , &p[i].y );
    if ( n == 2 )
    {
        printf ( "%d\n" , ((p[0].x - p[1].x ) * ( p[0].x - p[1].x )) + ( p[0].y - p[1].y ) * ( p[0].y - p[1].y )) ;
        return 0 ;
    }
    Graham();
    int maxx = 0 ;
    if ( top < 0 )
    {
        maxx = dis ( p[0] , p[n-1] );
    }
    else
    for ( i = 0 ; i < top ; i++ )
    {
        for ( j = i + 1 ; j < top ; j++ )
        {
            int len = dis( q[i] ,q[j] );
            if ( len > maxx )
            maxx = len ;
        }
    }
    printf ( "%d\n" , maxx );
    return 0 ;
}

用旋转卡壳(110ms)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <string>
#define N 50005
using namespace std ;

struct node
{
    int x ;
    int y ;
}p[N] , q[N] ;

int n , top ;

int dis ( struct node p1 , struct node p2 )
{
    return ( ( p1.x - p2.x ) * ( p1.x - p2.x ) + ( p1.y - p2.y ) * ( p1.y - p2.y ));
}

int cross ( struct node p1 , struct node p2 , struct node p0 )
{
    return ( ( p1.x - p0.x ) * ( p2.y - p0.y ) - ( p2.x - p0.x ) * ( p1.y - p0.y ));
}

int cmp ( struct node p1 , struct node p2 )
{
    if ( cross( p1 , p2 , p[0] ) > 0 )
    return 1 ;
    if ( cross ( p1 , p2 , p[0] ) == 0 && dis( p1, p[0] ) < dis( p2 , p[0] ))
    return 1 ;
    return 0 ;
}

void Graham ()
{
    int i , j , k ;
    k = 0 ;
    for ( i = 1 ; i < n ; i++ )
    if ( ( p[i].y < p[k].y ) || ( p[i].y == p[k].y && p[i].x < p[k].x ))
    k = i;

    struct node tem = p[k] ;
    p[k] = p[0] ;
    p[0] = tem ;

    sort ( p , p + n , cmp );

    top = 0 ;
    q[top++] = p[0] ;
    q[top++] = p[1] ;
    q[top++] = p[2] ;
    for ( i = 3 ; i < n ; i++ )
    {
        while ( cross ( p[i] , q[top-1] , q[top-2] ) >= 0 )
        top-- ;
        q[top++] = p[i] ;
    }
}

int max (int a , int b)
{
    return a > b ? a : b ;
}

int rotating_calipers()
{
    int j = 1 , ans = 0 ;
    q[top] = q[0] ;
    for(int i = 0 ; i < top ; i++ )
    {
        while(cross( q[i+1] , q[j+1] , q[i] ) > cross( q[i+1] , q[j] , q[i] ))
        j = ( j + 1 ) % top ;
        ans = max( ans , max( dis( q[i] , q[j] ) , dis( q[i+1] , q[j+1] )));
    }
    return ans;
}

int main()
{
    int i , d ;
    scanf ( "%d" , &n ) ;
    for ( i = 0 ; i < n ; i++ )
    scanf ( "%d%d" , &p[i].x , &p[i].y );
    if ( n == 2 )
    {
        d = dis ( p[0] , p[1] );
        printf ( "%d\n" , d );
        return 0 ;
    }
    Graham();
    if ( top < 0 )
    {
        d = dis ( p[0] , p[n-1] );
    }
    else
    {
        d = rotating_calipers();
    }
    printf ( "%d\n" , d );
    return 0 ;
}

 

 

 

posted @ 2012-07-18 15:15  Misty_1  阅读(212)  评论(0编辑  收藏  举报