我竟然A了 worldfinal 的水题
n<=15
所以可以列举每一种情况
状态压缩
#include<stdio.h> #include<algorithm> #include<string.h> #include<stack> #include<math.h> using namespace std; #define MAXN 20 #define INF 100000000 class point { public: int x,y,v,len; int operator ^(point b) { return x*b.y-y*b.x; } point operator -(point b) { point c; c.x=x-b.x; c.y=y-b.y; return c; } }x[MAXN],res[MAXN],tur[MAXN]; int ans,cut_len,MIN_val,MIN_CNT; double left; double Dis(point p1,point p2) { return sqrt(double((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y))); } bool cmp(point a,point b) { int tmp=((a-res[0])^(b-res[0])); if(tmp>0) return 1; if(tmp==0&&Dis(a,res[0])<Dis(b,res[0])) return 1; return 0; } stack<point>s; double tubao(int num) { if(num==0)//这3个特判 return 0; if(num==1) return 0; if(num==2) return 2*Dis(res[0],res[1]); int k=0; //扫描法 凸包 for(int i=1;i<num;i++) if(res[i].y<res[k].y) k=i; else if(res[i].y==res[k].y&&res[i].x<res[k].x) k=i; swap(res[0],res[k]); sort(res+1,res+num,cmp); while(!s.empty()) s.pop(); s.push(res[0]); s.push(res[1]); point a,b; for(int i=2;i<num;i++) { b=s.top(); s.pop(); a=s.top(); while(s.size()>1&&((res[i]-b)^(b-a))>=0) { b=a; s.pop(); a=s.top(); } s.push(b); s.push(res[i]); } int len=0; while(!s.empty()) { tur[len++]=s.top(); s.pop(); } double dis=0; for(int i=0;i<len-1;i++) dis+=Dis(tur[i],tur[i+1]); dis+=Dis(tur[len-1],tur[0]); return dis; } int main() { int n,ca; ca=1; while(scanf("%d",&n)!=EOF&&n) { if(ca!=1) printf(" "); for(int i=0;i<n;i++) scanf("%d%d%d%d",&x[i].x,&x[i].y,&x[i].v,&x[i].len); int ed=1<<n; MIN_CNT=MIN_val=INF; for(int i=0;i<ed;i++)//列举每一种情况 { int cnt=0,num=0,val=0; double cut=0; for(int j=0;j<n;j++) if(i&(1<<j)) { cnt++; cut+=x[j].len; val+=x[j].v; } else { res[num++]=x[j]; } double dis=tubao(num); if(dis>cut) continue; if(val<MIN_val||val==MIN_val&&cnt<MIN_CNT)//维护失去权值最小 { ans=i; MIN_val=val; MIN_CNT=cnt; left=cut-dis; } } printf("Forest %d ", ca++); printf("Cut these trees:"); for(int i=0;i<n;i++) if(ans&(1<<i)) printf(" %d",i+1); printf(" Extra wood: %.2lf ",left); } return 0; }