程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> POJ 1873 The Fortified Forest(凸包+枚舉)

POJ 1873 The Fortified Forest(凸包+枚舉)

編輯:C++入門知識

題目:給出一些樹,每棵樹有坐標,高度,以及價值,要求砍掉一些樹,用那些木材,將其它樹圍起來,要求花最小的代價,代價相同,要求砍掉最少的樹。
 因為只有15棵樹,狀態壓縮枚舉所有狀態,2^15次方,然後對剩下的樹求一次凸包,求出凸包周長,判斷木材是否夠用,記錄最優解。
第一道WF的題,水~~~~
幾個地方注意:
當只剩下1、2棵樹的時候,記得要特判
[cpp]
#include<iostream> 
#include<cstdio> 
#include<cstring> 
#include<cmath> 
#include<vector> 
#include<string> 
#include<algorithm> 
#include<queue> 
#define LL long long 
#define eps 1e-7 
#define N 2000000 
#define MOD 1000000007 
#define inf 1<<30 
#define zero(a) (fabs((double)(a))<eps) 
using namespace std; 
struct Point{ 
    int x,y,v,l; 
}p[15]; 
int n; 
//存放沒有被砍的樹 
vector<Point>a; 
//叉積 
int xmul(Point p0,Point p1,Point p2){ 
    return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x); 

//計算距離 
double dist(Point p1,Point p2){ 
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y)); 

//極角排序 
bool cmp(Point p1,Point p2){ 
    if(xmul(a[0],p1,p2)>0) return true; 
    else if(zero(xmul(a[0],p1,p2))&&dist(a[0],p1)<dist(a[0],p2)) return true; 
    return false; 

double Grham_scan(int len){ 
    //如果只剩下一棵樹就不用圍了 
    if(a.size()==1) return len; 
    //如果只剩下兩棵樹,那就是二者距離和的2倍,注意是2倍,可以從樣例中看出來 
    else if(a.size()==2) return len-dist(a[0],a[1])*2; 
    for(int i=1;i<a.size();i++) 
        if(a[i].y<a[0].y||(a[i].y==a[0].y&&a[i].x<a[0].x)) 
            swap(a[0],a[i]); 
    sort(a.begin()+1,a.end(),cmp); 
    vector<Point>s; 
    s.push_back(a[0]);s.push_back(a[1]);s.push_back(a[2]); 
    for(int i=3;i<a.size();i++){ 
        while(s.size()>=2&&xmul(s[s.size()-2],s[s.size()-1],a[i])<eps) 
            s.pop_back(); 
        s.push_back(a[i]); 
    } 
    s.push_back(s[0]); 
    double ans=0; 
    //求凸包周長 
    for(int i=0;i<s.size()-1;i++) 
        ans+=dist(s[i],s[i+1]); 
    return len-ans; 

int main(){ 
    int cas=0; 
    while(scanf("%d",&n)!=EOF&&n){ 
        for(int i=0;i<n;i++) 
            scanf("%d%d%d%d",&p[i].x,&p[i].y,&p[i].v,&p[i].l); 
        //最優解的代價,砍掉樹目的數量,最優狀態 
        int best_val=inf,best_num,best_state; 
        //最優解剩下的木材 
        double best_extra; 
        //枚舉 
        for(int i=1;i<(1<<n)-1;i++){ 
            int tmp_val=0,tmp_len=0; 
            a.clear(); 
            for(int j=0;j<n;j++){ 
                if(!((1<<j)&i)) 
                    a.push_back(p[j]); 
                else{ 
                    tmp_len+=p[j].l; 
                    tmp_val+=p[j].v; 
                } 
            } 
            //小小剪枝 
            if(tmp_val>best_val)  continue; 
            double extra=Grham_scan(tmp_len); 
            //如果extra<0說明不夠用 
            if(extra>=0){ 
                if(tmp_val<best_val){ 
                    best_val=tmp_val; 
                    best_num=n-a.size(); 
                    best_state=i; 
                    best_extra=extra; 
                } 
                else if(tmp_val==best_val&&n-a.size()<best_num){ 
                    best_num=n-a.size(); 
                    best_state=i; 
                    best_extra=extra; 
                } 
            } 
        } 
        printf("Forest %d\nCut these trees:",++cas); 
        for(int i=0;i<n;i++) 
            if((1<<i)&best_state)  printf(" %d",i+1); 
        printf("\nExtra wood: %.2f\n\n",best_extra); 
    } 
    return 0; 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved