显然我们取的肯定是前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
",l);
return 0;
}