迭代加深搜索思想。
枚举答案K,考虑到能否切出K个木头,那么我们当然选最小的K个来切。
1、对于原材料,我们是首选最大的还是最小的?显然,首选大的能够更容易切出,也更容易得到答案。
2、对于目标木头,我们是优先得到最大的还是最小的?显然,由于K个木头我们都要得到,那么当然先把最大的(最难得到的)先得到,这种搜索策略更优。
3、假设总原材料为all,前K个木头总和为sum,那么all-sum就是这一次切割过程中能【浪费】的最大数目。对于一个切剩下的原材料,若它比最小的目标木头还要小,则它可视为【无用】的,无用的也就是浪费的,若浪费>all-sum,则直接返回false
4、对于一个目标木头B,若它的长度和上一个木头A的长度相同,那么我们切B所用的原材料(B')一定是从切A所用的原材料(A')位置开始找。(这其实就是一个剪掉重复计算的剪枝)
5、迭代可以使用二分,但其实枚举也慢不了多少。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m,a[55],b[1100],maxs=0,sums[1100];
int mid;
bool cmp(int x,int y)
{
return x>y;
}
bool dfs(int ia,int ib,int sum,int all)
{
if(ib==0) return true;
if(sum>all) return false;
for(int i=ia;i<=n;i++)
{
if(a[i]>=b[ib])
{
a[i]-=b[ib];
int tmp=sum+(a[i]<b[1]?a[i]:0);
int st=(b[ib]==b[ib-1]?i:1);
if(dfs(st,ib-1,tmp,all))
{
a[i]+=b[ib];
return true;
}
a[i]+=b[ib];
}
}
return false;
}
int main()
{
freopen("fence8.in","r",stdin);
freopen("fence8.out","w",stdout);
int all=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
all+=a[i];
maxs=max(maxs,a[i]);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&b[i]);
if(b[i]>maxs) {i--;m--;}
}
sort(a+1,a+1+n,cmp);
sort(b+1,b+1+m);
for(int i=1;i<=m;i++)
sums[i]=sums[i-1]+b[i];
int l=0,r=m,ans;
for(ans=0;ans<=m&&dfs(1,ans,0,all-sums[ans]);ans++) ;
printf("%d\n",ans-1);
return 0;
}