Description
农夫约翰打算建立一个栅栏将他的牧场给围起来,因此他需要一些特定规格的木材。于是农夫约翰到木材店购买木材。可是木材店老板说他这里只剩下少部分大规格的木板了。不过约翰可以购买这些木板,然后切割成他所需要的规格。而且约翰有一把神奇的锯子,用它来锯木板,不会产生任何损失,也就是说长度为10的木板可以切成长度为8和2 的两个木板。
你的任务:给你约翰所需要的木板的规格,还有木材店老板能够给出的木材的规格,求约翰最多能够得到多少他所需要的木板。
你的任务:给你约翰所需要的木板的规格,还有木材店老板能够给出的木材的规格,求约翰最多能够得到多少他所需要的木板。
Input
第一行为整数m(m≤50)表示木材店老板可以提供多少块木材给约翰。紧跟着m行为 老板提供的每一块木板的长度。接下来一行(即第m+2行)为整数n(n≤1000),表示约翰需要多少木材。接下来n行表示他所需要的每一块木板的长度。 木材的规格小于32767。(对于店老板提供的和约翰需要的每块木板,你只能使用一次)。
Output
只有一行,为约翰最多能够得到的符合条件的木板的个数。
Sample Input
4
30
40
50
25
10
15
16
17
18
19
20
21
25
24
30
Sample Output
7
HINT
25切出21
30切出20
40切出19、18
50切出 15、16、17
Source
迭代加深搜索+剪枝
迭代加深搜索思想。
枚举答案K,考虑到能否切出K个木头,那么我们当然选最小的K个来切。
1、对于原材料,我们是首选最大的还是最小的?显然,首选大的能够更容易切出,也更容易得到答案。
2、对于目标木头,我们是优先得到最大的还是最小的?显然,由于K个木头我们都要得到,那么当然先把最大的(最难得到的)先得到,这种搜索策略更优。
3、假设总原材料为all,前K个木头总和为sum,那么all-sum就是这一次切割过程中能【浪费】的最大数目。对于一个切剩下的原材料,若它比最小的目标木头还要小,则它可视为【无用】的,无用的也就是浪费的,若浪费>all-sum,则直接返回false
4、对于一个目标木头B,若它的长度和上一个木头A的长度相同,那么我们切B所用的原材料(B')一定是从切A所用的原材料(A')位置开始找。(这其实就是一个剪掉重复计算的剪枝)
5、迭代可以使用二分,但其实枚举也慢不了多少。
#include<stdio.h>
#include<algorithm>
using namespace std;
int a[55],b[1010],c[1010];
int max1(int a,int b){return a>b?a:b;}
bool cmp(int a,int b){return a>b;}
int n,m;
bool dfs(int l,int r,int sum,int p)
{
if(r==0)return 1;
if(sum>p)return 0;
for(int i=l;i<=m;i++)
{
if(a[i]>=b[r])
{
a[i]-=b[r];
int q=(a[i]<b[1]?a[i]:0);
l=(b[r]==b[r-1]?i:1);
if(dfs(l,r-1,sum+q,p)){a[i]+=b[r];return 1;}
a[i]+=b[r];
}
}
return 0;
}
int main()
{
int maxx,all;
maxx=0;
all=0;
scanf("%d",&m);
for(int i=1;i<=m;i++){scanf("%d",&a[i]);all+=a[i];maxx=max1(maxx,a[i]);}
scanf("%d",&n);
for(int i=1;i<=n;i++){scanf("%d",&b[i]);if(b[i]>maxx){i--;n--;}}
int ans;
sort(a+1,a+m+1,cmp);
sort(b+1,b+n+1);
c[1]=b[1];
for(int i=2;i<=n;i++)c[i]=c[i-1]+b[i];
for(ans=1;ans<=n&&dfs(1,ans,0,all-c[ans]);ans++);
printf("%d",ans-1);
return 0;
}
/**************************************************************
Problem: 1269
User: xrq
Language: C++
Result: Accepted
Time:4 ms
Memory:968 kb
****************************************************************/