看了很久了的题了,集训的时候就看过,每棵树有自己的价值和长度,现在要砍掉一些书做成栅栏,来围起剩余的树,并要使砍掉的树价值总和最小。
当时觉得有价值,树也有砍与不砍2种状态,就觉得这是DP,然后在死胡同里绕啊绕~~后来才发现,树2<=n<=15.。。好吧其实枚举每棵树是否砍掉,然后记录最小价值比较下求凸包就可以了。。
要从数据量上推算法啊!
//Memory: 216K //Time: 172MS #include <stdio.h> #include <string.h> #include <math.h> #include <algorithm> #include <iostream> using namespace std; #define INF 10000000 int anscut[16]; //最后是要砍哪些树 int cnt; double value[20],tlong[20]; //每棵树的价值和长度 bool cut[16]; //标记是否砍了 struct POINT { double x,y; };POINT p[20],ch[20],tc[20]; //p为总树,ch为凸包的树,tc为砍后剩下的树 double dist(POINT a,POINT b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); } double multiply(POINT sp,POINT ep,POINT op) { return (sp.x-op.x)*(ep.y-op.y)-(ep.x-op.x)*(sp.y-op.y); } bool cmp(POINT a,POINT b) { if( multiply(a,b,tc[0]) > 0 || ( multiply(a,b,tc[0]) == 0 && dist(tc[0],a) < dist(p[0],b) )) return 1; return 0; } double Graham_scan(int n) //凸包,需要考虑剩余1棵树和2棵树的情况,返回凸包周长 { if(n==1 || n==0) return 0; if(n==2) return 2*dist(tc[0],tc[1]); memset(ch,0,sizeof(ch)); int i,k=0,top=2; double l=0; POINT tmp; for(i=1;i<n;i++) if(tc[i].y < tc[k].y || ( tc[i].y == tc[k].y ) && ( tc[i].x < tc[k].x )) k=i; tmp=tc[0]; tc[0]=tc[k]; tc[k]=tmp; sort(tc+1,tc+n,cmp); ch[0]=tc[0]; ch[1]=tc[1]; ch[2]=tc[2]; for(i=3;i<n;i++) { while(multiply(tc[i],ch[top],ch[top-1]) >= 0) top--; ch[++top]=tc[i]; } ch[++top]=ch[0]; for(i=0;i<top;i++) l+=dist(ch[i],ch[i+1]); return l; } double solve(int n) { int cutall=int(pow(2.0,double(n))); double al,el,ans; double mv=INF,val; int i,j,k,t; for(i=1;i<cutall;i++) { k=i; j=0; t=0; al=0; val=0; memset(cut,0,sizeof(cut)); memset(tc,0,sizeof(tc)); while(j<n) //用2进制数来模拟砍掉哪些树,二进制每一位若为1,对应的树则砍掉 { if(k&1==1) { cut[j]=1; al+=tlong[j]; val+=value[j]; } else { tc[t++]=p[j]; //没砍的加入求凸包的队伍中 } k=k>>1; j++; } if(val<mv) { el=al-Graham_scan(t); if(el>=0) { mv=val; cnt=0; ans=el; for(int d=0;d<n;d++) if(cut[d]) anscut[cnt++]=d; } } } return ans; } int main() { int n,i,cas=1; while(~scanf("%d",&n)) { if(n==0) break; for(i=0;i<n;i++) { scanf("%lf%lf%lf%lf",&p[i].x,&p[i].y,&value[i],&tlong[i]); } double ans=solve(n); if(cas!=1) printf("\n"); printf("Forest %d\n",cas++); printf("Cut these trees:"); for(i=0;i<cnt;i++) printf(" %d",anscut[i]+1); printf("\nExtra wood: %.2lf\n",ans); } return 0; }