题目描述
农夫约翰打算建立一个栅栏将他的牧场给围起来,因此他需要一些特定规格的木材。于是农夫约翰到木材店购买木材。可是木材店老板说他这里只剩下少部分大规格的木板了。不过约翰可以购买这些木板,然后切割成他所需要的规格。而且约翰有一把神奇的锯子,用它来锯木板,不会产生任何损失,也就是说长度为10的木板可以切成长度为8和2的两个木板。
你的任务:给你约翰所需要的木板的规格,还有木材店老板能够给出的木材的规格,求约翰最多能够得到多少他所需要的木板。
输入输出格式
输入格式:第一行为整数m(m<= 50)表示木材店老板可以提供多少块木材给约翰。紧跟着m行为老板提供的每一块木板的长度。
接下来一行(即第m+2行)为整数n(n <= 1000),表示约翰需要多少木材。
接下来n行表示他所需要的每一块木板的长度。木材的规格小于32767。(对于店老板提供的和约翰需要的每块木板,你只能使用一次)。
输出格式:只有一行,为约翰最多能够得到的符合条件的木板的个数。
输入输出样例
输入样例#2: 复制
3 20 10 10 9 3 3 3 5 5 7 8 8 9
输出样例#2: 复制
7
一道标准的深搜题,注意剪枝,dfs中las用于如果上一个长度如果和现在的一样的话就可以不用枚举前面的了,sum是前缀和,用于剪枝(具体实现看代码),还有w是记录有多少被浪费了,即当前一段木板
被使用后剩余的连最短的也无法符合;
要求答案的话就先排序,在二分答案
#include<bits/stdc++.h> using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch>'9'||ch<'0') {if(ch=='-') f=getchar();ch=getchar();} while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();} return f*x; } int n,m,a[55],b[1010],sum[1010],tot=0,w,mid,ans=0; bool dfs(int deep,int las){ if(deep==0) return 1; if(tot-w<sum[mid]) return 0; bool ok=0; for(int i=las;i<=n;i++){ if(b[deep]<=a[i]){//注意等号 卡了很久才发现。。 a[i]-=b[deep];if(a[i]<b[1]) w+=a[i]; if(b[deep]==b[deep-1]) ok=dfs(deep-1,i); else ok=dfs(deep-1,1); if(a[i]<b[1])w-=a[i];a[i]+=b[deep]; if(ok) return 1; } } return 0; } int main(){ m=read(); for(int i=1;i<=m;i++) a[i]=read(),tot+=a[i]; n=read(); for(int i=1;i<=n;i++) b[i]=read(); sort(a+1,a+m+1); sort(b+1,b+n+1); for(int i=1;i<=n;i++) sum[i]=sum[i-1]+b[i]; while(sum[n]>tot)n--; int l=0,r=n; while(l<=r){ w=0,mid=l+r>>1; if(dfs(mid,1)==1) ans=mid,l=mid+1; else r=mid-1; } cout<<ans<<endl; return 0; }