POJ 1873 The Fortified Forest(枚举+凸包+剪枝)

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 ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值