POJ1837:凸包+状态压缩

POJ1873

题意

  • 砍掉树把剩下的树围起来,要求花费最小。如果花费相同,求砍掉的树最少。

题解

  • 状态压缩枚举砍掉的树。求剩下树的凸包和周长。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
int const N = 15 + 5;
double const inf = 1e10;
double const eps = 1e-8;
int n;
vector<int>ans,tmp;
struct Tree
{
	double x,y,v,l;
}tree[N];
int dcmp(double x){
	if(fabs(x) < eps)	return 0;
	else return x < 0 ? -1 : 1;
}
struct Point 
{
	double x,y;
	Point(){};
	Point(double x,double y):x(x),y(y){};
	Point operator - (const Point& e)const{
		return Point(x - e.x,y - e.y);
	}	
	double operator ^ (const Point& e)const{
		return x * e.y - y * e.x;
	}
	bool operator < (const Point& e)const{
		return x < e.x || (x == e.x && y < e.y);
	}
};
Point p1[N],p2[N],ch[N];
int convex(Point *p,int n,Point *ch){
	sort(p,p+n);
	int m = 0;
	for(int i=0;i<n;i++){
		while(m > 1 && ((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 && ((ch[m-1] - ch[m-2]) ^ (p[i] - ch[m-2])) <= 0)	m--;
		ch[m++] = p[i];
	}
	if(n > 1)	m--;
	return m;
}
double dis(Point a,Point b){
	return hypot(a.x - b.x,a.y - b.y);
}
double getlen(Point *p,int n){
	double ans = 0;
	for(int i=0;i<n;i++)
		ans += dis(p[i],p[(i+1)%n]);
	return ans;
}
int main(){
	int caser = 0;
	while(~scanf("%d",&n) && n){
		for(int i=0;i<n;i++)
			scanf("%lf%lf%lf%lf",&tree[i].x,&tree[i].y,&tree[i].v,&tree[i].l);
		double minval = inf,extralen;	
		ans.clear();
		for(int i=0;i<(1<<n);i++){   //状态压缩枚举砍掉的树
			double val = 0,len1 = 0,len2 = 0;
			int m1 = 0,m2 = 0;
			tmp.clear();
			for(int j=0;j<n;j++){
				if(i & (1<<j)){
					tmp.push_back(j);
					val += tree[j].v;
					len1 += tree[j].l;  //能够围住的长度
				}else 
					p2[m2++] = Point(tree[j].x,tree[j].y);
			}
			if(val > minval)	continue;   //加这一条件,否则超时
			int num = convex(p2,m2,ch);
			len2 = getlen(ch,num);  //凸包的周长
			if(dcmp(len1 - len2) < 0)	continue;
			if(dcmp(minval - val) > 0 || (!dcmp(minval - val) && m1 < ans.size())){
				ans = tmp;
				minval = val;
				extralen = len1 - len2;
			}
		}
		printf("Forest %d\n",++caser);
		printf("Cut these trees: ");
		for(int i=0;i<ans.size();i++)	printf("%d ",ans[i] + 1);
		printf("\n");
		printf("Extra wood: %.2f\n",extralen);
		printf("\n");
	}
	return 0;
}

 

猜你喜欢

转载自blog.csdn.net/weixin_42264485/article/details/89072309