POJ 1873 The Fortified Forest
题意:
某王有一些树,要制作一个栅栏将所有树围起来,栅栏制作木材来源就是砍去其中一些树。
现在输入每棵树的坐标,价值,高度,求出所围价值最大且砍伐数目最小的方案。
思路:
嗯,1999年WF的水题。。
由于树木只有最多十五颗,那么枚举砍伐方案,然后求出剩余树木的凸包,比较得到最优→_→
但是啊,但是,POJ卡常数简直毫无人性啊!!!UVA和UVALive上相同题目86msAC的代码放POJ怒吃TLE。。
最后做了一点剪枝才放了过去。。(如果剩余树木小于等于3,直接求周长;如果砍伐树木总价值已超过目前最优价值,则直接跳过)
代码:
/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
#include<queue>
using namespace std;
#define clr( x , y ) memset(x,y,sizeof(x))
#define cls( x ) memset(x,0,sizeof(x))
#define mp make_pair
#define pb push_back
typedef long long lint;
typedef long long ll;
typedef long long LL;
const double eps = 1e-8 ;
const double pi = acos( -1.0 ) ;
inline double sqr( double x ){ return x * x ; }
int sgn( double x ){
if( fabs( x ) < eps ) return 0 ;
if( x > eps ) return 1 ;
return -1 ;
}
struct Point{
double x , y ;
double v , l ;
Point( double a = 0 , double b = 0 ) : x(a) , y(b) {}
void input(){
scanf( "%lf%lf%lf%lf" , &x , &y , &v , &l ) ;
}
double norm(){
return sqrt( sqr( x ) + sqr( y ) );
}
friend Point operator + ( const Point &a , const Point &b ){ return Point( a.x + b.x , a.y + b.y ) ; }
friend Point operator - ( const Point &a , const Point &b ){ return Point( a.x - b.x , a.y - b.y ) ; }
friend Point operator * ( const Point &a , const double &b ){ return Point( a.x*b , a.y*b ) ; }
friend Point operator / ( const Point &a , const double &b ){ return Point( a.x/b , a.y/b ) ; }
};
typedef Point Vector ;
double dot( Vector a , Vector b ){ return a.x * b.x + a.y * b.y ; }
double det( Vector a , Vector b ){ return a.x * b.y - a.y * b.x ; }
bool cmp_less( const Point a , const Point b ){
return sgn( a.x - b.x ) < 0 || ( sgn( a.x - b.x ) == 0 && sgn( a.y - b.y ) < 0 );
}
double ConvexHull( Point *p , int n , Point *ch ){
sort( p , p+n , cmp_less ) ;
int m = 0 ;
for( int i = 0 ; i < n ; i++ ){
while( m > 1 && det( ch[m-1] - ch[m-2] , p[i] - ch[m-2] ) <= 0 ) m-- ;
ch[m++] = p[i] ;
}
int k = m ;
for( int i = n - 2 ; i >= 0 ; i-- ){
while( m > k && det( ch[m-1] - ch[m-2] , p[i] - ch[m-2] ) <= 0 ) m-- ;
ch[m++] = p[i] ;
}
if( n > 1 ) m-- ;
double sum = 0 ;
ch[m] = ch[0] ;
for( int i = 0 ; i < m ; i++ ) sum += ( ch[i+1] - ch[i] ).norm() ;
return sum ;
}
const int maxn = 20 ;
Point pt[maxn] , ch[maxn] , p[maxn] ;
int main(){
//freopen( "input.txt" , "r" , stdin ) ;
int n , kase = 1 ;
while( scanf( "%d" , &n ) != EOF && n ){
cls( ch ) ;
int sumw = 0 , sumv = 0 ;
for( int i = 0 ; i < n ; i++ ){
pt[i].input() ;
sumw += pt[i].l ;
sumv += pt[i].v ;
}
double val = 0 , wood = 0 ;
int num = n ;
int ans ;
for( int i = 1 ; i < ( 1 << n ) ; i++ ){
double tmpv = 0 , tmpw = sumw ;
int len = 0 ;
for( int j = 0 ; j < n ; j++ ){
if( i & ( 1 << j ) ){
tmpv += pt[j].v ;
tmpw -= pt[j].l ;
p[len++] = pt[j] ;
}
}
if( tmpv < val ) continue ;
double cosw ;
if( len == 1 ) cosw = 0 ;
else if( len == 2 ) cosw = 2 * ( p[0] - p[1] ).norm() ;
else if( len == 3 ) cosw = ( p[0] - p[2] ).norm() + ( p[2] - p[1] ).norm() + ( p[1] - p[0] ).norm();
else{
cosw = ConvexHull( p , len , ch ) ;
}
if( cosw > tmpw ) continue ;
if( tmpv > val || ( tmpv == val && num > n - len ) ){
val = tmpv ;
wood = tmpw - cosw ;
num = n - len ;
ans = i ;
}
}
if( kase != 1 ) puts("") ;
printf( "Forest %d\n" , kase++ ) ;
printf( "Cut these trees:" ) ;
for( int i = 0 ; i < n ; i++ ) if( !( ans & ( 1 << i ) ) )
printf( " %d" , i+1 ) ;
printf( "\nExtra wood: %.2f\n" , wood ) ;
}
return 0 ;
}