【训练题9:多重背包的二进制拆分】宝物筛选 | 洛谷 P1776

   日期:2020-11-14     浏览:90    评论:0    
核心提示:多重背包的二进制拆分难度题意数据范围思路核心代码【普通多重背包】核心代码【二进制拆分】宝物筛选 | 洛谷 P1776难度绿题绿题绿题题意一个 普通 的多重背包物品数 NNN 背包容积 VVV每个物品有重量 wiw_iwi​ 价值 viv_ivi​ 物品数 cic_ici​求装完之后的最大价值和数据范围1≤n≤1001\le n\le 1001≤n≤1000≤V≤4×1040\le V\le 4\times10^40≤V≤4×104∑ci≤105\sum c_i\le 10^5∑ci​

多重背包的二进制拆分

    • 难度
    • 题意
    • 数据范围
    • 思路
    • 核心代码【普通多重背包】
    • 核心代码【二进制拆分】

宝物筛选 | 洛谷 P1776

难度

绿 题 绿题 绿

题意

一个 普通 的多重背包
物品数 N N N 背包容积 V V V
每个物品有重量 w i w_i wi 价值 v i v_i vi 物品数 c i c_i ci
求装完之后的最大价值和

数据范围

1 ≤ n ≤ 100 1\le n\le 100 1n100
0 ≤ V ≤ 4 × 1 0 4 0\le V\le 4\times10^4 0V4×104
∑ c i ≤ 1 0 5 \sum c_i\le 10^5 ci105

思路

【普通方法】

  • 对于每个物品,可以选择 1 ∼ c i 1\sim c_i 1ci
  • 转移: d p [ j ] = max ⁡ { d p [ j ] , d p [ j − k ∗ w [ i ] ] + k ∗ v [ i ] } dp[j]=\max\{dp[j],dp[j-k*w[i]]+k*v[i]\} dp[j]=max{ dp[j],dp[jkw[i]]+kv[i]}
  • 时间复杂度 O ( N V ∑ c i ) O(NV\sum c_i) O(NVci)
  • 经过一个数量循环优化以及O2优化,可以勉强卡过去、、
  • (开启了O2优化之后的时间)

【二进制拆分】

  • 重点来了!
  • 由于一个物品数量特别多,我们需要对其进行优化。
  • 假设一个物品有17个,我们可以把它拆成:17=1+2+4+8+2
  • 前面几个数分别是 2的幂次方 , 最后一个数字为 个数减去前面的幂次方的和(或者叫做拆分的补足)
  • 我们可以对这几个数字进行选取,于是可以选出所有[1,17]范围内的所有数字
  • 选取数字的过程,正好就是01背包选取物品的过程。
  • 这样,每个物品的个数 C i C_i Ci 被我们减少成 log ⁡ C i \log C_i logCi
  • 总体时间复杂度即为 O ( N V ∑ log ⁡ C i ) O(NV\sum\log C_i) O(NVlogCi)
  • (同样开启了O2优化的二进制拆分的时间)
  • (无O2优化的正常代码时间)

核心代码【普通多重背包】

时间复杂度 O ( N V ∑ C i ) O(NV\sum C_i) O(NVCi)


const int MAX = 4e4+50;

int v[MAX];
int w[MAX];
int cnt[MAX];
int dp[MAX];
int main()
{ 
    int N,W;
    cin >> N >> W;
    for(int i = 1;i <= N;++i){ 
        cin >>  v[i] >> w[i] >> cnt[i];
    }
    for(int i = 1;i <= N;++i){ 
        for(int j = W;j >= w[i];--j){ 
            for(int k = 1;k <= cnt[i];++k){ 
                if(j - k * w[i] < 0)break;
                dp[j] = max(dp[j],dp[j - k * w[i]] + k * v[i]);
            }
        }
    }
    cout << dp[W];
    return 0;
}

核心代码【二进制拆分】

时间复杂度 O ( N V ∑ log ⁡ C i ) O(NV\sum\log C_i) O(NVlogCi)


const int MAX = 2e5+50;

int v[MAX];
int w[MAX];
int dp[MAX];
int main()
{ 
    int N,W;
    int ct = 0;
    cin >> N >> W;
    for(int i = 1;i <= N;++i){ 
        int tx,ty,tz;
        cin >> tx >> ty >> tz;
        for(int j = 1;j <= tz;j <<= 1){ 
            v[++ct] = tx * j;
            w[ct]   = ty * j;
            tz -= j;
        }
        if(tz){ 
            v[++ct] = tx * tz;
            w[ct]   = ty * tz;
        }
    }
    for(int i = 1;i <= ct;++i){ 
        for(int j = W;j >= w[i];--j){ 
            dp[j] = max(dp[j],dp[j-w[i]] + v[i]);
        }
    }
    cout << dp[W];
    return 0;
}
 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服