UVA 811 - The Fortified Forest(凸包)

题目:The Fortified Forest


题意:二维平面上有n棵树,每棵树用一个点(x,y)表示,同时还有树自身的价值v以及用这棵树造栅栏的长度l。

现在要用其中一些树来当材料建造栅栏将剩下的树围起来,要求当材料的树的价值应该最小,如果多种情况符合,则取个数最少那个。

要求输出用作材料的树的编号以及造完栅栏后剩下的材料长度。


因为n<=15,所以可以直接枚举要砍的树,计算出砍下的树的总长度len,然后对剩下的点求凸包,计算凸包的周长used,如果len>=used说明当前方案可行,根据题目要求进行选择即可。


#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
using namespace std;
const int inf = 0x7fffffff;
const double eps = 1e-8;
struct Point{
	double x, y;
	Point(){}
	Point(double x, double y):x(x),y(y){}
	bool operator < (const Point &tmp)const{
		return x<tmp.x || (fabs(x-tmp.x)<eps&&y<tmp.y);
	}
	Point operator + (Point A){
		return Point(x+A.x, y+A.y);
	}
	Point operator - (Point A){
		return Point(x-A.x, y-A.y);
	}
};
double dis(Point &A, Point &B){
	return sqrt((A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y));
}
double det(Point A, Point B){
	return A.x*B.y - A.y*B.x;
}
int n, v[20], l[20];
Point p[20];
vector<Point> V;
Point ch[20];
double ex, used;
double ConvexHull(){//返回凸包周长
	int m = 0;
	sort(V.begin(), V.end());
	for(int i=0; i<V.size(); i++){
		while(m>1 && det(ch[m-1]-ch[m-2], V[i]-ch[m-2])<=0)	m--;
		ch[m++] = V[i];
	}
	int k = m;
	for(int i=V.size()-2; i>=0; i--){
		while(m>k && det(ch[m-1]-ch[m-2], V[i]-ch[m-2])<=0)	m--;
		ch[m++] = V[i];
	}
	double res = 0;
	for(int i=0; i<m-1; i++){
		res += dis(ch[i], ch[i+1]);
	}
	return res;
}
int main(){
	int ct = 0;
	while(~scanf("%d", &n) && n){
		if(ct)	puts("");
		for(int i=0; i<n; i++){
			scanf("%lf %lf", &p[i].x, &p[i].y);
			scanf("%d %d", v+i, l+i);
		}
		int ans=inf, st, cnt, tmp, len;
		for(int i=1; i<(1<<n); i++){
			V.clear();
			tmp = 0;
			len = 0;
			for(int j=0; j<n; j++){
				if(i&(1<<j)){
					tmp += v[j];
					len += l[j];
				}
				else{
					V.push_back(p[j]);
				}
			}
			//这里做个剪枝,如果当前方案就算可行也不比当前优的话,则忽略。
			if(tmp>ans || (tmp==ans && (n-V.size())>=cnt))	continue;
			used = ConvexHull();
			if(len>=used){
				ans = tmp;
				cnt = n-V.size();
				st = i;
				ex = len - used;
			}
		}
		printf("Forest %d\n", ++ct);
		printf("Cut these trees:");
		for(int j=0; j<n; j++){
			if(st&(1<<j))	printf(" %d", j+1);
		}
		puts("");
		printf("Extra wood: %.2lf\n", ex);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值