• 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;
    }
    



  • 相关阅读:
    如何删除完全重复的列
    串联多个字符串,引发string和stringBuilder的比较
    借鉴ANJOU的方法改写了上次的TreeView
    如何改变ListBox中内容的顺序
    执行Insert语句时使用string的Format用法
    moss 2007 中FCKEditor编辑器的使用
    qt 获得cmd 命令运行的结果 GIS
    迭代器 GIS
    win32 创建带图片的button GIS
    c++标准库的构成 GIS
  • 原文地址:https://www.cnblogs.com/keshuqi/p/5957707.html
Copyright © 2020-2023  润新知