多重背包详解

前置知识

首先需要知道0-1背包,0-1背包大概就是对于一定数量的物品,每种物品只存在选与不选两种状态,而且每种物品只有1个,也就是说对于每种物品要么放进背包要么不放进背包两种情况,最后可以通过滚动数组的方式以O(n)的空间复杂度完成相关题目
在这里插入图片描述

多重背包的概念

多重背包就是对于每种物品都有多个,与0-1背包的区别仅仅是每种物品的数量存在多个,如图
在这里插入图片描述

解决思路

朴素的解决方法是将每种物品的数量展开,然后按照0-1背包的思路逐个遍历求解,最后就能得到最终结果,但这样的时间复杂度非常高,假如物品的数量非常多,全部展开再一个一个求解显然有点慢,那么应该怎么优化呢?

对于展开求解,实际是一个一个求解,如果上过数电课,这时应该很容易想到任何数字都可以用二进制来快速表示,比如5可以用4+1也就是2的0次方+2的2次方来表示,优化时也是使用了这个思想,也就是二进制优化

二进制优化

对于多重背包的二进制优化,并不是简单的像9=8+1这样直接转化为二进制(这个实际是状态转移方向),这也是因为每个物品的选取可以是1-9个,所以二进制优化的方向应该是用二进制表示1-9的任意一个数,比如9应该等于2的0次方+2的1次方+2的2次方+2,再加上二进制正好可以表示两种状态,也就是将多个物品优化成了n位二进制物品,所以这个方向也几乎是合理的

二进制优化后的状态转移

初学多重背包时总会钻个牛角尖,如对于背包容量为4,但是如何保证重量为1的物品选取了4个?
在这里插入图片描述
按照前面说的,5 = 1+2+2,看上去好像选不到4对不对?
在这里插入图片描述
在0-1背包中,先遍历物品再遍历背包,由一维数组从后往前遍历,尝试将每一个物品放入,这里也一样,将每个二进制表示看成一个物品,所以先求将1个物品放入,接着将2个物品放入,然后由于已经求出了放入一个物品的价值,这时候2个物品放入背包后的价值自然由1个物品放入背包状态转移得到

同理,背包容量为4要想放入4个物品自然是从之前已经放入2个物品的状态得到,这样就有一个状态转移链,即4->2->1

模板题

如果还是不理解,不妨试试这道模板题,做完再看看相信也能理解了
洛谷 P1776

C++代码

#include<bits/stdc++.h>
using namespace std;

int n,W;
int v[10000000];
int w[10000000];
int dp[10000000];


void getval(){
	for(int i=1; i<=n; ++i){
		for(int j=W; j>=w[i]; --j){
			dp[j] = max(dp[j], dp[j-w[i]] + v[i]);
		}
	}
}

int main(){
	int tmpv, tmpw, m;
	int k =0;
	scanf("%d%d", &n, &W);
	for(int i=1; i<=n; ++i){
		scanf("%d%d%d", &tmpv, &tmpw, &m);
		for(int j=1; j<=m; j<<=1){
			k++;
			v[k] = tmpv*j;
			w[k] = tmpw*j;
			m -= j;
		}
		if(m > 0){
			k++;
			v[k] = tmpv*m;
			w[k] = tmpw*m;
		}
	}
	n = k;
	getval();
	printf("%d", dp[W]);
	return 0;
}

总结

  1. 多重背包可以转化为0-1背包求解,但由于时间复杂度的关系,需要优化,根据0-1背包的特点与状态转移的方向,可以用二进制优化数量
  2. 二进制优化目的是用二进制表示1-n个物品的数量,这样既能保证dp状态转移选取数量时可以覆盖1-n的任何数量的物品,也加快了选取的速度

后话

  1. 由于本人学识浅薄,仅仅只是从程序的角度去思考多重背包,实际上多重背包的优化涉及到数学知识,如有兴趣可以参考其他资料
  2. 文章中如有错误,希望各位大佬能在评论区指出
  • 14
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值