POJ 1873 The Fortified Forest (凸包,状态压缩枚举)

来源:互联网 发布:淘宝内裤真人秀在哪看 编辑:程序博客网 时间:2024/06/09 14:19

题目链接:http://poj.org/problem?id=1873


题意:给出一些树,每棵树有坐标,高度,以及价值,要求砍掉一些树,用那些木材,将其它树围起来,要求花最小的代价,代价相同,要求砍掉最少的树。

最后输出要砍掉哪几棵树和最后剩下多少长度的木材。


输入:

6
 0  0  8  3
 1  4  3  2
 2  1  7  1
 4  1  2  3
 3  5  4  6
 2  3  9  8
3
 3  0 10  2
 5  5 20 25
 7 -3 30 32
0


n棵树,每行一棵,坐标,价值,高度。


因为树的棵数不多,所以可以直接状态压缩枚举来做,枚举时要注意判断砍0棵树的情况。

2^15次方,然后对剩下的树求一次凸包,求出凸包周长,判断木材是否够用,记录最优解。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <vector>#include <queue>#include <cmath>using namespace std;const double eps = 1e-8;const double PI = acos(-1.0);int sgn(double x) {if(fabs(x) < eps)return 0;if(x < 0)return -1;  else return 1; }struct Point {  double x,y, v, l;Point(){}  Point(double _x,double _y) {   x = _x;y = _y;  }  Point operator -(const Point &b)const {   return Point(x - b.x,y - b.y);  }  double operator ^(const Point &b)const {   return x*b.y - y*b.x;  }    double operator *(const Point &b)const {   return x*b.x + y*b.y;  }  void transXY(double B) {   double tx = x,ty = y;   x = tx*cos(B) - ty*sin(B);   y = tx*sin(B) + ty*cos(B);  } };struct Line {  Point s,e; Line(){}  Line(Point _s,Point _e)  {   s = _s;e = _e;  } pair<int,Point> operator &(const Line &b)const {Point res = s;if(sgn((s-e)^(b.s-b.e)) == 0) {if(sgn((s-b.e)^(b.s-b.e)) == 0) return make_pair(0,res);             else return make_pair(1,res);         }         double t = ((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));res.x += (e.x-s.x)*t;         res.y += (e.y-s.y)*t;         return make_pair(2,res);     } };double dist(Point a,Point b) {     return sqrt((a-b)*(a-b)); }const int MAXN = 1010; Point list[MAXN]; int Stack[MAXN], top;bool _cmp(Point p1,Point p2) {  double tmp = (p1-list[0])^(p2-list[0]);  if(sgn(tmp) > 0)return true;  else if(sgn(tmp) == 0 && sgn(dist(p1,list[0]) - dist(p2,list[0])) <= 0)   return true;  else return false; }void Graham(int n) {Point p0;int k = 0;p0 = list[0];  for(int i = 1;i < n;i++)  {   if( (p0.y > list[i].y) || (p0.y == list[i].y && p0.x > list[i].x) )   {    p0 = list[i];    k = i;   }  }  swap(list[k],list[0]);  sort(list+1,list+n,_cmp); if(n == 1)  {top = 1;Stack[0] = 0;return;}if(n == 2)  {   top = 2;   Stack[0] = 0;   Stack[1] = 1;   return ;  }  Stack[0] = 0;  Stack[1] = 1;  top = 2;  for(int i = 2;i < n;i++)  {   while(top > 1 && sgn((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]])) <= 0)top--;   Stack[top++] = i;  } } Point tree[20];int main() {int n;int kase = 1; while(~scanf("%d", &n), n) { printf("Forest %d\n", kase++); int i, j; for(i = 0; i < n; i++) { scanf("%lf %lf %lf %lf", &tree[i].x, &tree[i].y, &tree[i].v, &tree[i].l); } double ansc = 10000000, ansl;int anst[20];int num = 0; for(i = 0; i < 1 << n; i++) { int cnt = 0; double len1 = 0, len2 = 0, cost = 0; for(j = 0; j < n; j++) { if(i >> j & 1) { list[cnt++] = tree[j]; } else { len2 += tree[j].l; cost += tree[j].v; } } if(cnt == 0) continue;  //砍0棵树  Graham(cnt); for(j = 0; j < top; j++) { len1 += dist(list[Stack[j]], list[Stack[(j + 1) % top]]); } if(len1 <= len2) { if(ansc > cost) { ansc = cost; ansl = len2 - len1; num = 0; for(j = 0; j < n; j++) { if(!(i >> j & 1)) { anst[num++] = j; } } } else if(ansc == cost){ if(n - cnt < num) { ansc = cost; ansl = len2 - len1; num = 0; for(j = 0; j < n; j++) { if(i >> j & 1) { anst[num++] = j; } } } } } } printf("Cut these trees:"); for(i = 0; i < num; i++) { printf(" %d", anst[i] + 1); } printf("\n"); printf("Extra wood: "); printf("%.2lf\n\n", ansl); }return 0;}


0 0
原创粉丝点击