【Usaco】Fence8

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
****************************************************************/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值