POJ 1873

按位枚举,按最小价值,最小砍掉树剪枝就好了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

using namespace std;
const int MAXN=20;
const int inf=190000000;
int n,l;

int st[MAXN],stop,cnt;
int ans[MAXN];
bool cut[MAXN];
struct point{
	int x,y;
	int len,val;
	int num;
}p[MAXN];
int ansV,ansC;
double anslen;
bool cmp(point A,point B){
	if(A.y<B.y) return true;
	else if(A.y==B.y){
		if(A.x<B.x) return true;
	}
	return false;
}

bool cmp1(int a,int b){
	if(a<b) return true;
	return false;
}

bool multi(point a,point b,point c){
	return (a.x-c.x)*(b.y-c.y)-(a.y-c.y)*(b.x-c.x)<=0;
}

double dist(point a, point b){
	return sqrt((a.x-b.x)*(a.x-b.x)*1.0+(a.y-b.y)*(a.y-b.y)*1.0);
}

double for_len(){
	if(cnt==1) return 0;
	double res=0;
	for(int i=1;i<cnt;i++)
	res+=dist(p[ans[i]],p[ans[i-1]]);
	return (res);
}

void slove(){
	stop=0; cnt=0;
	int choice=0; int be;
	for(int i=0;i<n;i++){
		if(!cut[i]){
			st[stop++]=i;
			choice++;
		}
		if(choice==2){ 
			be=i;
			break;
		}
	}
	if(choice<2){ cnt=1; return ; }
	for(int i=be+1;i<n;i++){
		if(cut[i]) continue;
		while(stop>1&&multi(p[st[stop-1]],p[i],p[st[stop-2]])) stop--;
		st[stop++]=i;
	}
	for(int i=0;i<stop;i++){
		ans[cnt++]=st[i];
	}
	stop=0; choice=0;
	for(int i=n-1;i>=0;i--){
		if(!cut[i]){
			st[stop++]=i;
			choice++;
		}
		if(choice==2){ be=i; break; }
	}
	for(int i=be-1;i>=0;i--){
		if(cut[i]) continue;
		while(stop>1&&multi(p[st[stop-1]],p[i],p[st[stop-2]])) stop--;
		st[stop++]=i;
	}
	for(int i=0;i<stop;i++)
	ans[cnt++]=st[i];
}

int main(){
	int cas=0;
	while(scanf("%d",&n)!=EOF){
		if(n==0) break;
		cas++;
		for(int i=0;i<n;i++){
			scanf("%d%d%d%d",&p[i].x,&p[i].y,&p[i].val,&p[i].len);
			p[i].num=i+1;
		}
		sort(p,p+n,cmp);
		ansV=inf; int tmpV; int tmpC; double len; int CUT=inf;
		for(int i=1;i<(1<<n);i++){
			tmpV=0; tmpC=0; len=0;
			memset(cut,false,sizeof(cut));
			for(int k=0;k<n;k++){
				if((1<<k)&i){
					cut[k]=true;
					tmpV+=p[k].val;
					tmpC++;
					len+=p[k].len;
				}
			}
			if(tmpV<ansV){
				slove();
				double res=for_len();
				if(res<=len){
					CUT=tmpC;
					ansV=tmpV;
					ansC=i;
					anslen=len*1.0-res;
				}
			}
			else if(tmpV==ansV){
				if(CUT>tmpC){
					slove();
					double res=for_len();
					if(res<=len){
						CUT=tmpC;
						ansV=tmpV;
						ansC=i;
						anslen=len*1.0-res;
					}
				}
			}
		}
		printf("Forest %d\n",cas);
		printf("Cut these trees:");
		cnt=0;
		for(int k=0;k<n;k++)
		if((1<<k)&ansC){
			st[cnt++]=p[k].num;
		}
		sort(st,st+cnt,cmp1);
		for(int i=0;i<cnt;i++)
		printf(" %d",st[i]);
		printf("\n");
		printf("Extra wood: %0.2lf\n",anslen);
		printf("\n");
	}
	return 0;
}

  

posted @ 2014-07-31 21:25  chenjunjie1994  阅读(224)  评论(0编辑  收藏  举报