背包问题整理

多重背包II中的二进制拆分
for(int i=1;i<=n;i++)
{
    int a,b,s;cin>>a>>b>>s;//体积、价值、数量
    int k=1;
    while(k<=s)
    {
        w[++cnt]=a*k,v[cnt]=b*k;
        s-=k;
        k*=2;
    }
    // cout<<"s=="<<s<<endl;
    if(s)
        w[++cnt]=a*s,v[cnt]=b*s;
}

y总的混合背包(精简的二进制拆分)
#include <iostream>

using namespace std;

const int N = 1010;

int n, m;
int f[N];

int main()
{
    cin >> n >> m;

    for (int i = 0; i < n; i ++ )
    {
        int v, w, s;
        cin >> v >> w >> s;
        if (!s)
        {
            for (int j = v; j <= m; j ++ )
                f[j] = max(f[j], f[j - v] + w);
        }
        else
        {
            if (s == -1) s = 1;
            for (int k = 1; k <= s; k *= 2)
            {
                for (int j = m; j >= k * v; j -- )
                    f[j] = max(f[j], f[j - k * v] + k * w);
                s -= k;
            }
            if (s)
            {
                for (int j = m; j >= s * v; j -- )
                    f[j] = max(f[j], f[j - s * v] + s * w);
            }
        }
    }

    cout << f[m] << endl;

    return 0;
}
金明的预算方案中十分有借鉴意义的二进制枚举方法
for (int i = 1; i <= n; i ++ )
        for (int u = m; u >= 0; u -- )
        {
            for (int j = 0; j < 1 << servent[i].size(); j ++ )//2^n(n是附件的个数)种方案,从0~2^n-1
            {
                int v = master[i].v, w = master[i].w;
                for (int k = 0; k < servent[i].size(); k ++ )//位运算枚举    2的n次方-1二进制表示有n位,从最高位开始枚举可以右移
                // 0~n-1位
                    if (j >> k & 1)
                    {
                        v += servent[i][k].v;
                        w += servent[i][k].w;
                    }
                if (u >= v) f[u] = max(f[u], f[u - v] + w);
            }
    }
posted @ 2021-01-15 11:45  30天CF上蓝!!!  阅读(56)  评论(0编辑  收藏  举报