多重背包问题的二进制优化(C语言)

在这里插入图片描述
之前一直不理解,为什么多重背包与01背包是类似的
用朴素法解决多重背包时,操作的集合分为不取i物品,取一个i物品,取两个i物品……取s个物品
所以解题的思路就是在01背包的基础上再加一重循环,将以上集合的全部列举出来,选择其中的价值最大值
代码如下

#include<stdio.h>
int v[1005],w[1005],s[1005],dp[1005];
int main()
{
	int n,m,i,j,k;
	scanf("%d%d",&n,&m);
	for(i = 1;i <= n;i++)
		scanf("%d%d%d",&v[i],&w[i],&s[i]);
	for(i = 1;i <= n;i++)
		for(j = m;j >= v[i];j--)
			for(k = 1;k <= s[i]&&k*v[i] <= j;k++) 
				if(dp[j] < dp[j-k*v[i]]+k*w[i])
					dp[j] = dp[j-k*v[i]]+k*w[i];
	printf("%d",dp[m]);
}

但是三重循环,在测试数据较强的情况下,时间复杂度是不符合要求的
所以有了二进制优化
什么是二进制优化呢?比如现在有10个苹果,我们显然可以用十个箱子,第一个箱子装1个苹果,第二个箱子装2个苹果……第十个箱子装10个苹果
这样满足了如果我们想要n个苹果,取出第n个箱子就可以
但是可以想象到,如果我们现在有数量很大的苹果,用同样数目的箱子来一个一个装肯定是不现实的
二进制优化就在此时引入
还是10个苹果的例子,我们可以进行如下的减法
10 - 1 = 9
9 - 2 = 7
7 - 4 = 3
3 - 8 < 0
这样我们就可以只需要4个箱子
第一个箱子装1个,第二个箱子装2个,第三个箱子装4个,第四个箱子装3个
可以证明,用这四个箱子,可以得到1~10中的任意一个数
那么我们就可以借用这个思想,将多重背包问题简化成01背包问题
物品对应箱子,物品的体积和价值相应的变为数量乘以单个物品的体积和价值
这样一来我们只需要在01背包代码进行简单的改动,就可以AC了

#include<stdio.h>
struct Good{
	int v_;
	int w_;
}good[10000];//装有多重背包退化成01背包的物品
int dp[2005];
int main()
{
	int n,m,k = 1;
	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i++){
		int v,w,s;
		scanf("%d%d%d",&v,&w,&s);
		for(int j = 1;j <= s;j*=2){//对物品数目按照二进制进行装填
			good[k].v_ = v*j;
			good[k].w_ = w*j;
			s-=j;
			k++;
		}
		if(s){//剩余物品(也就是例子中的3-8不够减的3)
			good[k].v_ = v*s;
			good[k].w_ = w*s;
			k++;
		}
	}
	for(int i = 1;i <= k-1;i++)
		for(int j = m;j >= good[i].v_;j--){
			if(dp[j] < dp[j-good[i].v_]+good[i].w_)
				dp[j] = dp[j-good[i].v_]+good[i].w_;
		}
	printf("%d",dp[m]);
}

这样一来
就实现了二进制的优化了,还是降低了挺多的
再回忆一下
例如当物品数量为3时
将其分为体积和价值为一个物品和两个物品的A、B
在滚动数组中
当判断是否能装入第A个物品时,实际上就是朴素思想的s = 1
当判断是否能装入第B个物品时,若装得下且剩余背包容量装不下A时,就是s = 2
若装得下且剩余背包容量也装得下A时,就是s = 3
嗯,是对的 ^ _ ^

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值