题意:国王想建一个周长最短的城墙,使墙的任意一点到城墙的距离都 > L。求这面墙的周长。
我们知道在每个顶点的时候要计算弧度,其实我们知道每个都变形最后所有的弧形加起来会组成一个以L为半径的圆;这样周长就转换为凸包的周长+圆的周长;
这里我自己写了两种关于Graham-scan不同的排序法;
极角排序:
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> #include<set> #include<map> #include<cstring> #include<vector> using namespace std; class Point { public: int x,y; }point[1024]; int multi( Point p1 , Point p2 , Point q ) { return ( p1.x - q.x )*( p2.y - q.y ) - ( p2.x - q.x )*( p1.y - q.y ); } double Distance( Point a , Point b ) { return sqrt(( double )( a.x - b.x )*( a.x - b.x )+( a.y - b.y )*( a.y - b.y )); } bool cmp( Point a, Point b ) { int t = multi( a , b , point[0]); if( t > 0 ) return true; else if( t == 0 && Distance( a , point[0] ) < Distance( b , point[0] ) ) return true; return false; } double Length( Point p[] , int len , int L ) { double dis = acos( -1.0 ) * L * 2; for( int i = 1 ; i < len ; i ++) { dis += Distance( p[i-1] , p[i] ); } dis += Distance( p[0] , p[len-1] ); return dis; } int main( ) { int N,L; while( scanf( "%d %d",&N,&L )==2 ) { Point p[1024]; int len = 0; for( int i = 0 ; i < N ; i ++ ) { scanf( "%d %d",&point[i].x,&point[i].y ); if( point[i].y < point[0].y ) swap( point[i] , point[0] ); } sort( point + 1 , point + N , cmp ); for( int i = 0 ; i < N ; i++ ) { while( len >=2 && multi( p[len-1] , point[i] ,p[len-2] ) < 0 ) len--; p[len++] = point[i]; } printf( "%.0f\n",Length( p , len , L ) ); } //system( "pause" ); return 0; }
水平排序:
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<queue> #include<set> #include<map> #include<cstring> #include<vector> using namespace std; class Point { public: int x,y; }point[1024]; bool cmp( Point a , Point b ) { if( a.y == b.y ) return a.x > b.x; return a.y > b.y; } double Distance( Point a, Point b ) { return sqrt( double(( a.x - b.x )*( a.x - b.x ) + ( a.y - b.y )*( a.y - b.y )) ); } int segment( Point p2 , Point p1, Point q ) { return ( p1.x - q.x )*( p2.y - q.y ) - ( p2.x - q.x )*( p1.y - q.y ); } double Graham( int N ,int L) { Point p[1024]; int len = 0; for( int i = 0 ; i < N ; i ++ ) { while( len >=2 && segment( point[i],p[len-1],p[len-2] )< 0 ) len --; p[len++] = point[i]; }; int t = len + 1; for( int i = N - 2; i >=0 ; i -- ) { while( len >= t && segment( point[i],p[len-1],p[len-2] )< 0 ) len --; p[len++] = point[i]; } double dis = acos(-1.0) * L *2.0; // printf( "%lf\n",dis ); for( int i = 1; i < len; i ++ ) { dis += Distance( p[i-1] , p[i] ); } return dis; } int main( ) { int N,L; while( scanf( "%d %d",&N, &L )==2 ) { for( int i = 0 ; i < N; i ++ ) { scanf( "%d %d",&point[i].x ,&point[i].y ); } sort( point , point + N , cmp ); printf( "%.0f\n",Graham( N ,L )); } //system( "pause" ); return 0; }