• bzoj1082[SCOI2005]栅栏


    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

    思路:

    首先,此题属于最小值最大化问题,果断下二分答案,而此题适用于left no   AND   right no   BUT   mid yes 的二分查找。

    唔,据网上blogs,背包动归的写法还不如搜索+剪枝,所以此题约等于贪心题目,于是有了:

    • 优化part 1:将店主可提供的木板和farmer John的需要木板进行排序。
    那么,暴搜的框架就不再赘述,下面我们看看此题的剪枝。。。
    可行性剪枝1:自然是搜完啦farmer John要买的最小mid个的木板后,向二分查找return 1咯。
    可行性剪枝2:累计切割后剩下不能再用的木板,计为waste,处理要买的木板的前缀和,计为s[],并且滴,累积商店里所有木板的长度为sum(好吧,tot||total||cnt也行,但是sum s是更和谐的),当s[mid](当前要买的mid个木板总长)+waste>sum时,也就是搜索目标最小值所用最优木板长度比可承受长度还长,那么剪枝。
    优化:当枚举的下一个要买到的木板长度和当前搞好的木板长度相同时,继续从当前商店的用过切过的木板i开始解决,否则从1开始。
    此题大概就是如此吧,具体的那些难以言表东西交给我的代码解决吧!
    二分答案技能get!
    //最近get技能read()函数,陷入三目运算符中不能自拔(表示noip不能用啊)。

    1592592

      ksq2013 1082 Accepted 828 kb 4 ms C++/Edit 1287 B 2016-08-15 17:16:48
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int l,r,mid,ans=0;
    int n,m,c[51],b[51],a[1001],s[1001]={0},sum=0;
    int read()
    {
        int x=0,c=getchar(),f=1;
        while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
        while(c>47&&c<58)x=x*10+c-48,c=getchar();
        return x*f;
    }
    bool dfs(int last,int waste,int cur)
    {
        if(!cur)return 1;
        if(waste+s[mid]>sum)return 0;
        for(int i=last;i<=m;i++)
            if(c[i]>=a[cur]){
                c[i]-=a[cur];
                int tmp=c[i]<a[1]?c[i]:0;
                int nxt=a[cur]==a[cur-1]?i:1;
                if(dfs(nxt,waste+tmp,cur-1))
                    return 1;
                c[i]+=a[cur];
            }
        return 0;
    }
    int main()
    {
        m=read();
        for(int i=1;i<=m;i++)
            b[i]=read(),sum+=b[i];
        n=read();
        for(int i=1;i<=n;i++)
            a[i]=read();
        sort(a+1,a+1+n);
        sort(b+1,b+1+m);
        for(int i=1;i<=n;i++)
            s[i]=s[i-1]+a[i];
        for(;s[n]>sum;n--);
        l=0,r=n;
        while(l<=r){
            mid=(l+r)>>1;
            memcpy(c,b,sizeof(b));
            if(dfs(1,0,mid))ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d
    ",ans);
        return 0;
    }
    



  • 相关阅读:
    HDU2059(龟兔赛跑)
    pat 1012 The Best Rank
    pat 1010 Radix
    pat 1007 Maximum Subsequence Sum
    pat 1005 Sign In and Sign Out
    pat 1005 Spell It Right
    pat 1004 Counting Leaves
    1003 Emergency
    第7章 输入/输出系统
    第六章 总线
  • 原文地址:https://www.cnblogs.com/keshuqi/p/5957707.html
Copyright © 2020-2023  润新知