迭代加深搜索思想。
枚举答案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; }
USACO/fence8 迭代加深搜索+剪枝,布布扣,bubuko.com
时间: 2024-10-19 07:25:48