【bzoj1082】栅栏[SCOI2005]
显然我们取的肯定是前ans块木板。然后砍的木材也应该是从小到大砍(如果小的木材可以满足条件,就一定不会去动大的木材)
所以两遍排序。
二分答案。
然后对于要取的每块木板,我们搜索它是在第x块木板上砍下来的。。
要加剪枝:
①如果砍下了这块木材然后这块木材小于第一块木板,那就失去价值,用t来记录。当t>tot-s[now],(tot是记录的所有给的木板长度),那么退出。
②如果b[now]==b[now-1]那么从当前点开始枚举就可以了,因为前面小的点都被跳过了
#include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> using namespace std; #define N 60 #define M 1010 int n,m; int tot,mid; int t; int a[N],b[M],c[N]; int s[M]; bool DFS(int now,int d) { if (!now) return true; if (t>tot-s[mid]) return false; for (int i=d;i<=m;i++) if (c[i]>=b[now]) { c[i]-=b[now]; if (c[i]<b[1]) t+=c[i]; if (b[now]==b[now-1]) { if (DFS(now-1,i)) return true; } else { if (DFS(now-1,1)) return true; } if (c[i]<b[1]) t-=c[i]; c[i]+=b[now]; } return false; } int work(int mid) { for (int i=1;i<=m;i++) c[i]=a[i]; t=0; return DFS(mid,1); } int main() { scanf("%d",&m); for (int i=1;i<=m;i++) scanf("%d",&a[i]),tot+=a[i]; scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d",&b[i]); sort(a+1,a+m+1); sort(b+1,b+n+1); for (int i=1;i<=n;i++) s[i]=s[i-1]+b[i]; while (s[n]>tot) n--; int l=0,r=n; while (l<r) { mid=(l+r)>>1; if (work(mid+1)) l=mid+1; else r=mid; } printf("%d\n",l); return 0; }