USACO6.3.1 Fence Rails(fence8)

来源:互联网 发布:留学生落户360天算法 编辑:程序博客网 时间:2024/06/14 17:59

把原木和新木快排一遍,每次二分枚举可以切的木块数,再去验证,这应该是一个比较好想代码又好写的思路。

验证时,设枚举的木块数为k。由贪心思想可知,我们挑前k小的新木来切割

一个特别关键的剪枝:统计切剩下的board(无法再切下rail)总和,这个值大于board总和减去rail总和,无解。

这个代码里写有解释,应该是很清楚的


/*ID:xsy97051LANG:C++PROG:fence8*/#include <iostream>#include <cstdio>#include <algorithm>using namespace std;int a[51],b[1024],b_sum[1024];int n,m,ans,sum;//验证时,设枚举的木块数为k。由贪心思想可知,我们挑前k小的新木来切割。bool check(int num,int now,int q,int limit){if(num==0) return 1;//统计切剩下的board(无法再切下rail)总和,这个值大于board总和减去rail总和,无解(此剪枝最关键)if(q>limit) return 0;if(b[num]!=b[num+1]) now=n;  //事实证明,每次先用大的原木切割会更快,因为相对来说,它能分的个数更多  for(int i=now;i>0;i--)  {    if(a[i]>=b_sum[num])     return 1;    if(a[i]>=b[num])    {      a[i]-=b[num];      if(check(num-1,i,q+(a[i]<b[1])?a[i]:0,limit))       {      a[i]+=b[num];      return 1;      }      a[i]+=b[num];    }  }   return 0;}//把原木和新木快排一遍,每次二分枚举可以切的木块数,再去验证。int erfen(int l,int r){  if(l==r) return l;  int mid=(l+r)/2+1;  if(check(mid,n,0,sum-b_sum[mid]))   return erfen(mid,r);  else  return erfen(l,mid-1);}int main(){freopen("fence8.in","r",stdin);freopen("fence8.out","w",stdout);cin>>n;for(int i=1;i<=n;i++){cin>>a[i];sum+=a[i];}int tep=sum;cin>>m;for (int i=1;i<=m;i++)cin>>b[i];  sort(a+1,a+n+1);sort(b+1,b+m+1);for(int i=1;i<=m;i++)b_sum[i]=b_sum[i-1]+b[i];  int flag=m; for(int i=1;i<=m;i++) { tep-=b[i];if(tep<0){flag=i;break;}  } cout<<erfen(0,flag)<<endl;return 0;}


0 0
原创粉丝点击