多重背包 II —— 二进制优化

多重背包 II —— 二进制优化

核心思想:转换成0~1背包问题。———— 对个体拆分后全部打散,反正能够保证从全局上使得所有情况依然存在就可以了。

  1. 核心思想前提建议先把多重背包朴素版算法搞清楚

    转换成0 ~ 1背包问题,对个体拆分后全部打散,反正能够保证从全局上使得所有情况依然存在就可以了。

  2. 举例分析(以下都使用该样例)

    在选取第i种物品时,该物品有134件,二进制划分为**1,2,4,8,16,32,64,134 - (1 + 2 + 4 + 8 + 16 + 32 + 64) = 7 **这几个数字,这几个数字就相当于0 ~ 1背包问题中的每种背包。

    仔细观察可知0 ~ 134内的任一数字均可由以上划分数字组合相加构成。这样即便打散后在宏观全局上仍然能够满足0~134的每种情况。

  3. 字母标准化

    在选取第i种物品时,该物品有s件,二进制划分为1,2,4,8,16,······,2k-1,2k,s - (1 + 2 + ··· + 2k)这几个数字,这几个数字就相当于0 ~ 1背包问题中的每种背包。

    仔细观察可知0 ~ s内的任一数字均可由以上划分数字组合相加构成。这样即便打散后在宏观全局上仍然能够满足0 ~ s的每种情况。

  4. 问题(只是几个帮助理解的小问题,上面已经理解的话可自行跳过)

    1. 问:在134被划分成1,2,4,8,16,32,64后已经可以组合出7 = 1+ 2 + 4了,为什么最后面还要搞个7?

      答:现在已经转换成0 ~ 1背包来考虑问题了,那么前面1,2,4这几个数字已经被用来组合成1 + 2 + 4 + 8 + 16 + 32 + 64 = 127了,就已经不能再使用了。这时候要是想要再组合成134那么必然还要在127的基础上再加一个7。

    2. 问:0 ~ 127的数字都可以凑满了,134也可以凑出来了,那么128 ~ 133该怎么凑?

      答:因为上面要凑134的时候又引入了一个数字7,并且0 ~ 127不需要这个7就可以轻松凑出来的,那么就有如下:

      133 = 126 + 7;

      132 = 125 + 7;

      131 = 124 + 7;

      ········

      ········

  5. 代码示例:

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 11000;
    int n, m;
    int v[N], w[N], f[2010];
    int main(){
    scanf("%d%d", &n, &m);
    int cnt = 0;
    for(int i = 1; i <= n; i ++){
    // v w s
    int a, b, s;
    scanf("%d%d%d", &a, &b, &s);
    int k = 1;
    while(k <= s){
    cnt ++;
    v[cnt] = k * a;
    w[cnt] = k * b;
    s -= k;
    k *= 2;
    }
    if(s > 0){// s只能 >0 或者 =0
    cnt ++;
    v[cnt] = s * a;
    w[cnt] = s * b;
    }
    }
    for(int i = 1; i <= cnt; i ++)
    for(int j = m; j >= v[i]; j --){
    f[j] = max(f[j], f[j - v[i]] + w[i]);
    }
    printf("%d", f[m]);
    return 0;
    }
posted @   ture?  阅读(279)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示