POJ 1873 The Fortified Forest 凸包 二进制枚举
n最大15,二进制枚举不会超时。枚举不被砍掉的树,然后求凸包
#include<stdio.h> #include<math.h> #include<algorithm> #include<iostream> #include <cstring> #define eps 1e-8 #define INF 1e9 using namespace std; const int MAXN = 20; struct Point { int x,y; int v,l; }; Point pot[MAXN]; int stck[MAXN],top; int sgn(double x) { if(fabs(x) < eps) return 0; return x < 0 ? -1:1; } int cross(Point p0,Point p1,Point p2) //计算叉积 p0p1 X p0p2 { return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x); } double dis(Point p1,Point p2) //计算 p1p2的 距离 { return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y)); } bool cmp(Point p1,Point p2) //极角排序函数,角度相同则距离小的在前面 { int tmp=cross(pot[0],p1,p2); if(tmp>0) return true; else if(tmp==0&&dis(pot[0],p1)<dis(pot[0],p2)) return true; else return false; } void init(int n) //输入,并把最左下方的点放在 pot[0]。并且进行极角排序 { int i,k; Point p0; p0 = pot[0]; k=0; for(i=1; i<n; i++) { if( (p0.y>pot[i].y) || ((p0.y==pot[i].y)&&(p0.x>pot[i].x)) ) { p0 = pot[i]; k=i; } } pot[k]=pot[0]; pot[0]=p0; sort(pot+1,pot+n,cmp); } void graham(int n) { int i; if(n==1) { top=0; stck[0]=0; } if(n==2) { top=1; stck[0]=0; stck[1]=1; } if(n>2) { for(i=0; i<=1; i++) stck[i]=i; top=1; for(i=2; i<n; i++) { while(top>0&&cross(pot[stck[top-1]],pot[stck[top]],pot[i])<=0) top--; top++; stck[top]=i; } } } Point p[MAXN]; int main() { // freopen("in.txt","r",stdin); int n, val, len, minv, maxn, ans; double exc; int Case = 0; while(~scanf("%d", &n) && n) { val = len = 0; for(int i=0; i<n; i++) { scanf("%d%d%d%d", &p[i].x, &p[i].y, &p[i].v, &p[i].l); val += p[i].v; len += p[i].l; } minv = INF; maxn = 0; for(int i=1; i< (1<<n)-1; i++) { int cnt, tmp ,v ,l; cnt = 0; tmp = i; v = val; l = len; for(int j=0; j<n; j++) { if(tmp&1) { pot[cnt++] = p[j]; v -= p[j].v; l -= p[j].l; } tmp >>= 1; } init(cnt); graham(cnt); double d = 0; for(int j=0; j<=top; j++) d += dis(pot[stck[j]], pot[stck[(j+1)%(top+1)]]); if(sgn(l - d) >= 0) { if(v < minv || (v == minv && cnt > maxn)) { minv = v; maxn = cnt; ans = i; exc = l - d; } } } printf("Forest %d\nCut these trees: ", ++Case); for(int i=0; i<n; i++) { if((ans&1) == 0) printf("%d ", i+1); ans >>= 1; } printf("\nExtra wood: %.2lf\n\n", exc); } return 0; }