题目链接:https://vjudge.net/problem/POJ-1873
题意:有n棵树,每棵树有坐标(x,y),价值v,长度l,问如何砍能砍掉最小价值为的树(价值相同则砍最少的树),能把其他树都围起来。
思路:由于n特别小,可以枚举砍掉的树,看是否可以围起剩下的树,每次枚举后求一个凸包的周长,看是否满足即可。我用的是dfs枚举,感觉用2进制枚举更好些。
#include<bits/stdc++.h> #include<cstdio> #include<cstring> #include<cmath> #include<vector> #include<map> #include<iostream> #include<algorithm> using namespace std; int N; struct point { double x,y; double v,l; point friend operator -(point a,point b) { return {a.x-b.x,a.y-b.y,a.v-b.v,a.l-b.l}; } }p[100005],s[100005],q[100005]; int w[100005]; struct node { int v,shu; double l; vector<int> ve; } ans; double dis(point a,point b) { point c=a-b; return sqrt(c.x*c.x+c.y*c.y); } double X(point a,point b) { return a.x*b.y-a.y*b.x; } int cmp(point a,point b) { double x=X(a-p[1],b-p[1]); if(x>0) return 1; if(x==0&&dis(a,p[1])<dis(b,p[1])) return 1; return 0; } double multi(point p1,point p2,point p3) { return X(p2-p1,p3-p1); } void zc(double v,double l,int h) { ans.v=v; ans.shu=h; ans.l=l; ans.ve.clear(); for(int i=1;i<=h;i++) ans.ve.push_back(w[i]); } void fun(double l,double v,int n,int h) { if(n<=1) { if(v<ans.v||(v==ans.v&&h<ans.shu)) zc(v,l,h); return; } if(n==2) { double sum=2*dis(p[1],p[2]); if(l-sum>=0.00000001&&(v<ans.v||(v==ans.v&&h<ans.shu))) zc(v,l-sum,h); return; } int k=1; for(int i=2; i<=n; i++) if(p[i].y<p[k].y||(p[i].y==p[k].y&&p[i].x<p[k].x)) k=i; swap(p[1],p[k]); sort(p+2,p+1+n,cmp); s[1]=p[1]; s[2]=p[2]; int t=2; for(int i=3; i<=n; i++) { while(t>=2&&multi(s[t-1],s[t],p[i])<=0) t--; s[++t]=p[i]; } double sum=0; for(int i=1; i<t; i++) { sum+=dis(s[i],s[i+1]); } sum+=dis(s[1],s[t]); if(l-sum>=0.00000001&&(v<ans.v||(v==ans.v&&h<ans.shu))) zc(v,l-sum,h); } void dfs(int len,double l,double v,int k,int h) { if(len==N+1) { fun(l,v,k,h); return; } w[h+1]=len; dfs(len+1,l+q[len].l,v+q[len].v,k,h+1); p[k+1]=q[len]; dfs(len+1,l,v,k+1,h); } int main() { int u=0; while(scanf("%d",&N)) { if(N==0) break; if(u>0) cout<<endl; ans.v=30000005; for(int i=1; i<=N; i++) cin>>q[i].x>>q[i].y>>q[i].v>>q[i].l; dfs(1,0,0,0,0); printf("Forest %d ",++u); printf("Cut these trees:"); for(int i=0;i<ans.ve.size();i++) cout<<" "<<ans.ve[i]; cout<<endl; printf("Extra wood: %.2lf ",ans.l); } return 0; }