多重背包问题【最终优化版】

本文介绍了如何使用二进制分组思想解决01背包问题,通过将物品打包成不同大小的堆,确保每个组合都能表示0到s的所有数。然后用动态规划解决01背包问题,找到价值最大的物品组合。代码展示了具体的实现过程。

分析

1、打包思想,

可以将s个i物品,打包成log s 个新的物品堆,一堆一堆的,通过每一堆的数,都能够拼出0~s的任何一个数,

例如,s:0~1023 ,那么我们就分为10堆 分别为 1/2/4/8/16/32/64/128/256/512

可以通过每堆都可以拼出0~1023的每一个数,

 2、思路怎么想的?

 3、代码怎么写?

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 25000 ;//为什么开25000,是因为 2000 * log2000 = 21000

int v[N] , w[N];
int n,m;
int f[N];//一维01背包优化

int main()
{
    cin>>n>>m;
    int cnt = 0;//分组的组别,即几号
    
    
    //1、预处理,枚举每一个物品,按二进制分组
    for( int i = 1 ; i<=n ; i++ )
    {
        int a , b , s;
        cin>>a>>b>>s;
        //1.分组
        int k = 1;//组别里面的个数1/2/4/8/16/...
        while(k <= s)
        {
            cnt ++;
            v[cnt] = a * k;//更新v和w,打包在一起
            w[cnt] = b * k;
            s -= k;//s减小
            k *= 2;//更新k
        }
        //2.剩余一组
        if(s > 0)
        {
            cnt ++;
            v[cnt] = a * s;
            w[cnt] = b * s;
        }
    }
    
    //2、01背包问题求解
    n = cnt;//枚举次数正式由个数变成组别数
    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;
}
//把自己菜哭了~

 思绪逆着时光在向后倒退,退回流逝的岁月,退到当年,退到那片绿色的草原和那些个红霞艳艳的傍晚...... 

                                    ---《平凡的世界》 第四十七章

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值