多重背包原理及优化思想

11 篇文章 0 订阅

多重背包

题意

  • 有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]
  • 求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。

基本想法

这题目和完全背包问题很类似。基本的方程只需将完全背包问题的方程略微一改即可,因为对于第i种物品有n[i]+1种策略:取0件,取1件……取n[i]件。令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值,则有状态转移方程:

f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wi7WcAWN-1591070878201)(../图库/1590670676451.png)]

朴素代码

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;

int n, m;
int v[N], w[N], s[N];
int f[N][N];

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

    for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i] >> s[i];

    for (int i = 1; i <= n; i ++ )
        for (int j = 0; j <= m; j ++ )
            for (int k = 0; k <= s[i] && k * v[i] <= j; k ++ ) // 第i个物品枚举0 - s[i]个
                f[i][j] = max(f[i][j], f[i - 1][j - v[i] * k] + w[i] * k);

    cout << f[n][m] << endl;
    return 0;
}

多重背包优化思想

  • 转换为01背包,把s拆成log(s)份
  • 例如:s【i】 = 65 。可以打包一起卖。 下面7个包裹,组合起来,涵盖了【1 - 65】所有值。
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dhw99RGb-1591070878209)(../../../../%E5%9D%9A%E6%9E%9C%E5%90%8C%E6%AD%A5%E6%96%87%E4%BB%B6%E5%A4%B9/%E6%88%91%E7%9A%84%E5%9D%9A%E6%9E%9C%E4%BA%91/%E7%AE%97%E6%B3%95/%E5%9B%BE%E5%BA%93/1590671986971.png)]
#include <iostream>

using namespace std;

const int N = 12010, M = 2010; // N = 2000 * log(2000)
// 核心:利用二进制把s份拆成 log(s) 份

int n,m;
int v[N], w[N];
int f[M];

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

    int cnt = 0;
    for(int i=1;i<=n;i++)
    {
        int a,b,s;
        cin >> a >> b >> s;
        int k = 1;
        while(k <= s)
        {
            cnt ++ ;
            v[cnt] = a * k;
            w[cnt] = b * k;
            s -= k;
            k *= 2;
        }
        if(s > 0) // 剩下的凑成一组
        {
            cnt ++ ;
            v[cnt] = a * s;
            w[cnt] = b * s;
        }
    }

    n = cnt; // 总共有cnt组,做一遍01背包

    for(int i=1;i<=n;i++)
        for(int j = m; j >= v[i]; j --)
            f[j] = max(f[j],f[j - v[i]] + w[i]);

    cout<<f[m]<<endl;
    return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值