Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 5737 | Accepted: 1636 |
Description
Input
Output
Sample Input
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
Sample Output
Forest 1 Cut these trees: 2 4 5 Extra wood: 3.16 Forest 2 Cut these trees: 2 Extra wood: 15.00
Source
题意:平面上有n棵树,现在要砍掉其中的一部分来做成篱笆将剩下的树包围起来,现在给出每棵树的坐标、价值和可以制造篱笆的长度,
求砍掉最少价值的树,将剩下的树包围起来,当两种方式的价值相同时,取砍掉树更少的方式。
题解:直接二进制暴力枚举砍掉的树,剩下的树求出凸包,再求周长,可行的话更新ans。
#include<cstring> #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<vector> #define PI 3.1415926 #define INF 0x3f3f3f3f const double eps=1e-12; #define _sign(x) ((x)>eps?1:((x)<-eps?2:0)) using namespace std; const int MAXN = 30; struct Point { double x,y; double l; int v; 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; } //绕原点旋转角度B(弧度值),后x,y的变化 void transXY(double B) { double tx = x,ty = y; x = tx*cos(B) - ty*sin(B); y = tx*sin(B) + ty*cos(B); } }; Point L[MAXN],P[MAXN]; int Stack[MAXN],top; int n; double dist(Point a,Point b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } int sgn(double x) { if(fabs(x)<eps)return 0; if(x<0)return -1; return 1; } //相对于L[0]的极角排序 bool _cmp(Point p1,Point p2) { double tmp = (p1-L[0])^(p2-L[0]); if(sgn(tmp) > 0)return true; else if(sgn(tmp) == 0 && sgn(dist(p1,L[0]) - dist(p2,L[0])) <= 0) return true; else return false; } void Graham(int m) { if(m<=1)return; Point p0; int k = 0; p0 = L[0]; //找最下边的一个点 for(int i = 1; i < m; i++) { if( (p0.y > L[i].y) || (p0.y == L[i].y && p0.x > L[i].x) ) { p0 = L[i]; k = i; } } swap(L[k],L[0]); sort(L+1,L+m,_cmp); if(m == 1) { top = 1; Stack[0] = 0; return; } if(m == 2) { top = 2; Stack[0] = 0; Stack[1] = 1; return ; } Stack[0] = 0; Stack[1] = 1; top = 2; for(int i = 2; i < m; i++) { while(top > 1 && sgn((L[Stack[top-1]]-L[Stack[top-2]])^(L[i]-L[Stack[top-2]])) <= 0) top--; Stack[top++] = i; } } int main() { //freopen("test.in","r",stdin); int ca=1; while(cin>>n&&n) { for(int i=0; i<n; i++) { scanf("%lf%lf%d%lf",&P[i].x,&P[i].y,&P[i].v,&P[i].l); } int m=0; int ans=INF,id=0; int num=0; double ss=99999999.0; for(int i=0; i<(1<<n); i++) { double ls=0; int sum=0; m=0; for(int j=0; j<n; j++) { if(i&(1<<j)) { ///选到的树 sum+=P[j].v; ls+=P[j].l; } else L[m++]=P[j];///剩下的树 } if(sum>ans)continue; Graham(m); double s=0; for(int j=0; j<top; j++) { ///求凸包周长 int u=Stack[j],v=Stack[(j+1)%top]; s+=dist(L[u],L[v]); } if(m<=1)s=0; if(ls>=s) { if(ans>sum) { ans=sum; num=n-m; id=i; ss=ls-s; } else if(ans==sum) { if(num>n-m) { ss=ls-s; id=i; num=n-m; } } } } if(ca!=1)cout<<endl; printf("Forest %d\n",ca++); printf("Cut these trees:"); for(int i=0; i<n; i++) { if(id&(1<<i))printf(" %d",i+1); } printf("\nExtra wood: %.2f\n",ss); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
poj 1873 The Fortified Forest(凸包)
原文地址:http://blog.csdn.net/acm_baihuzi/article/details/47430655