浅谈多重背包

多重背包,基础背包问题之三。


具体问题是这样的。一个容量为V的背包,还有一些物品(每个物品有具体的数量c),这些物品的体积w和价值p各不相同。求出能在不超过V的情况下尽可能的使价值最大。


对于多重背包问题,可以根据每个物品的数量分解成两种情况:
1.当c >= V / w时,相当于物品可以无限使用,即转化为完全背包求解。
2.当c < V / w时, 可转化为放物品的数量为1、2、3……c个,即转化为01背包求解。


但是上面这种方法的时间复杂度为O(V连加M),其中M为数量。这个复杂度是很大的,可以用二进制拆分优化一下。


二进制拆分:任何数num都可以拆分为2^k的加和的形式,即:
num = 2^k1 + 2^k2 + …… + 2^kn (其中kn可以取任意非负整数)
这样上面的第二种情况就可以利用这种方法进行优化,使遍历从1、2、3……c优化到1、2、4……2^k,时间复杂度为O(V连加logM)。这种优化程度就可以应对大部分题目了。(当然,对于一些卡时间的题目也不行,需要优先队列优化)。
还有一点,看懂这一点就能看懂二进制优化的核心了。
对于使用二进制拆分成的一组数字:1、2、4、8……,这些数字之间缺少3、5、6、7这样的数字,在遍历的时候没有遍历他们,因为这些数字可以由前面遍历过的数字拼凑合成。比如,3可以由1和2合成,5可以由1和4合成,以此类推。还有,比如,如果最终结果包含5,那在遍历的时候就可能记录1和4,也就是说最终结果是1和4这两件被拆分的物品,最后合到一起就是5了。
就是这种方法,使不用被遍历的数字也能出现在过程中,这就是二进制优化的精髓!


以下为程序流程:
void MultiplePack(int w, int p, int m)
{
if (w * m >= p)
{
CompletePack(w, p);
return;
}
int k = 1;
while (k < m)
{
ZeroOnePack(k * w, k * p);
m -= k;
k *= 2;
}
ZeroOnePack(m * w, m * p);

}


下面附上多重背包的模板:

#include <iostream>
#include <algorithm>
using namespace std;
#define MAXL 10001

int dp[MAXL], V, n, w, p, m;

void ZeroOnePack(int w, int p);
void CompletePack(int w, int p);
void MultiplePack(int w, int p, int m);

int main()
{
	cin >> V >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> w >> p >> m;
		MultiplePack(w, p, m);
	}
	cout << dp[V] << endl;
	return 0;
}

void MultiplePack(int w, int p, int m)
{
	if (w * m >= p)
	{
		CompletePack(w, p);
		return;
	}
	int k = 1;
	while (k < m)
	{
		ZeroOnePack(k * w, k * p);
		m -= k;
		k *= 2;
	}
	ZeroOnePack(m * w, m * p);
}

void ZeroOnePack(int w, int p)
{
	for (int j = V; j >= w; j--)
		dp[j] = max(dp[j - w] + p, dp[j]);
}

void CompletePack(int w, int p)
{
	for (int j = w; j <= V; j++)
		dp[j] = max(dp[j - w] + p, dp[j]);
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值