• 背包新得


    最近搞了许多背包的题,总结一下各自用法:

    01背包:各个商品最多一件,用for()时倒序保证只能取一次;

    完全背包:各个商品无限件,用for()时正序保证在背包范围内能一直取;

    多重背包:各个商品有a[i]件,对每个商品进行讨论,分成完全背包与01背包,拆分只学会了二进制拆分,代码如下:

    int ans=cnt[i],s=1;
                while(s<=ans)
                {
                    for(int j=C;j>=w[i]*s;j--) f[j]=max(f[j],f[j-w[i]*s]+v[i]*s);
                    ans-=s;s=s<<1;
                }
                for(int j=C;j>=w[i]*ans;j--) f[j]=max(f[j],f[j-w[i]*ans]+v[i]*ans);
    View Code

    混合背包:分成以上各个背包;

    遇到一道二维背包的题,搞了许久:

    很明显需要的O与N很小,但是各个气缸所累加的O,N就大多了,故背包的数组不能由各个气缸所累加的O,N决定;

    这个时候就要转换思维了,见以下代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1100;
    int O,N,n,w[maxn],a[maxn],b[maxn],f[30][80];
    //f[j][k]表示前i个气缸O为j,N为k时的最小重量。
    inline int read()                               
    {
        int x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
            if(ch=='-') ff=-1;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*ff;
    }
    inline void DP()
    {
        for(int i=1;i<=n;i++)    //依次枚举各个商品... 
            for(int j=O;j>=0;j--)  //01背包,倒序枚举各个O的容量... 
                for(int k=N;k>=0;k--) //01背包,倒序枚举各个N的容量...
                {
                    int T=j-a[i];      //1;用T表示O由上一个状态哪一个容量更新的... 
                    int L=k-b[i];     //2;用L表示N由上一个状态哪一个容量更新的...
                    if(T<0) T=0;     //最难理解的地方:由于所有气缸的总O,N的含量太大空间肯定 
                    if(L<0) L=0;    //开不下于是就要把符合条件的给缩小,即超过需要的就变成需要的 .
                    f[j][k]=min(f[j][k],f[T][L]+w[i]);
                }  //这里对其他的转移没有影响,(假如本状态由未超过需要的O与N转移得到则没有影响。 
    }             //假如由超过需要的转移过来,那就不用考虑,直接赋成0,加上当前的重量。) 
    int main()
    {
        freopen("1.in","r",stdin);
        O=read();N=read();n=read();
        for(int i=1;i<=n;i++)
        {
            a[i]=read();
            b[i]=read();
            w[i]=read();
        }
        memset(f,127,sizeof(f));
        f[0][0]=0;
        DP();
        cout<<f[O][N]<<endl;
        return 0;
    }

    对当初的理解确实很懵,不过我们如果从DP的本质讲,就好理解多了,由于逆序输出,只能有小的值更新大的值,由于还是01背包,每个物品只能取一次,每次遇到新的容量,我们都面临取不取的问题,

    不取则状态不变,取就要找到由哪一个状态转移过来,1,2就是这个意思,很明显如果T或L的值是负的即这一个缸的O,N就够需求了不需其他缸了,就可以直接把它的上一个状态设为f[0][0]这样就不会因大小问题干扰状态的转移了。这道题就完了。

  • 相关阅读:
    tp3.2和tp5的区别
    tp(调试模式,空操作,跨控制器调用,跨方法跳转--redirect(),框架语法,创建model模型)
    tp 连表查 分页 模糊查询
    thinkphp if和eq的区别
    js 面向对象例子
    JS字符串转换为JSON的四种方法笔记
    json在php中的使用之如何转换json为数组
    window.frames用法
    php js 数组排序
    控件常用
  • 原文地址:https://www.cnblogs.com/gcfer/p/10564365.html
Copyright © 2020-2023  润新知