01背包与完全背包:正序Or倒叙遍历背包数究竟什么区别

01背包与完全背包:正序Or倒叙遍历背包数究竟什么区别

第一次写, 真的菜鸡的感性理解,如有理解错误之处,希望评论区多多指导
刚开始学背包问题,虽然背代码很容易,但是着实蒙蔽
此篇小文希望给新手一些帮助,放代码!

//01背包问题
for(int i=1;i<=n;i++)
	{
		int v,w;
		cin>>v>>w;//边输入边处理
		for(int j=m;j>=v;j--)//倒叙遍历背包数
			f[j]=max(f[j],f[j-v]+w); 
	}
//完全背包问题
for(int i=1;i<=n;i++)
	{
		int v,w;
		cin>>v>>w;
		for(int j=v;j<=m;j++)//正序遍历背包数
		{
			f[j]=max(f[j],f[j-v]+w);
		}
	}

对比一下,确实区别就在一个倒序,一个正序

解决01背包问题时倒叙遍历背包数,是因为01背包问题每种物品只能装一次
如果正序遍历,那么当dp[大的背包数]更新:f[j]=max(f[j],f[j-v]+w)时,
因为dp[小的背包数]已经更新过了,且更新时dp[小的背包数]会影响dp[大的背包数]
原来的dp数组已经不是单纯的前i-1种物品更新的结果
换句话说,给dp[小的背包数]更新已经相当于装入一次此种类物品,
而dp[大的背包数] 更新时本身已经代表着装入一次此种物品,但由于用到dp[小的背包数],又装入了一次此种物品
不符合01背包问题只装入一次的设定
而这种情况恰恰时完全背包问题所期望的
所以解决完全背包问题时,我们采用正序遍历

那么再来看看倒序遍历
因为dp[大的背包数]并不会影响到dp[小的背包数]
所以更新每个背包数时,dp数组都是上一个循环产生的旧数组
代表的是仅仅是前i-1个物品装入更新的结果
所以相当于每次装入只是第一次装入此种物品
符合01背包只装入一次的设定

多重背包

数据范围较小的情况下,都可以将具有多件的物品拆分开来,转化为01背包问题
易知

  1. 任何数=1+1+1…+1
  2. 任何数==2^ 0x0+2^ 1x1+…+2^n*xn+剩余
    所以对应数据大小我们有两种处理方法
    1. 死拆
    2. 二进制拆分
int t=0;
	while(N--)//转化为01背包 
	{
		int a,b,c;
		cin>>a>>b>>c;
		while(c--)
		{
			v[t]=a;
			w[t++]=b;
		}
	 }
//二分拆分 
	int cnt=0;//组别 
	while(N--)
	{
		int a,b,c;//该种物品的单位体积,单位价值,总件数 
		cin>>a>>b>>c;
		int k=1;//一组内的件数 
		//1 2 4 8 16... 
		while(k<=s)
		{
			v[++cnt]=a*k;//该组的体积 
			w[cnt]=b*k;//价值 
			s-=k;//剩余件数 
			k*=2;//下一组的件数 
		}
		if(s>0)//如果还有没分完的 
		{
			v[++cnt]=a*s;
			w[cnt]=b*s;
		}
	}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

社恐不参团

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值