0/1背包问题限制条件(两个for循环互换)

0/1背包问题限制条件(两个for循环互换)

for(int i=0;i<N;i++){//这里是错误的示范 
	for(int j=0;j<=V;j++){
		dp[容量][物品数量]
	}
}

当i=n,此时意味着状态以比较到前n-1件物品(正在比较第n件物品)
背包容量从0开始向V递增

要是放不下就等于上一个状态,要是放得下就判断究竟是放入以后总价值大还是不放总价值大
假设V=1000;第一个物品的体积是1,dp[容量][物品数量]初始化为0

第一步:求dp[0][0](背包容量为0,物品为第一个,因为i从0开始取值,所以代码上是0)
因为背包容量为0,小于第一个物品的体积,所以dp[0][0]的值等于上一个状态的值=dp[0][-1],出现了越界的问题。

倘若将dp[物品数量][容量](此处已互换)位置互换,那么依然会存在越界的问题。

那么如果将j改成从1,开始取值呢?这样的话只能针对第一个物品的体积是1这种问题,因此我们需要将j改成从等于的物品的体积开始取值,这样就能够避免数组越界的问题了。
同时也能够省略掉判断背包大还是我手中的物品大了。注意注意,如果代码写成这样的话:

memset(dp,0,sizeof(dp));
for(int i=0;i<N;i++){
	for(int j=struct[i].vol;j<=V;j++){
			dp[i][j]=max(dp[i-1][j-struct[i].vol]+struct[i].val,dp[i-1][j]);
		}
	}
}

我们固然可以省略背包容量与物品体积的判断,但是这也会造成数据的不更新,极端情况假设,
物体1的体积为1,则dp[0][0]=0(由memset赋值),dp[0][1]~dp[0][V]的值都等于物品1的价值,接着
物体2的体积等于背包的最大容量-1(即V-1),那么我dp[1][0]~dp[1][V-2]的值都不会继承上一层的值,而是全部保持memset赋的初值0,dp[1][V-1]=物品2的价值或是物品1的价值,dp[1][V]=物品1的价值+物品2的价值。接着
物品3的体积等于2,此时从dp[2][2]开始,dp[2][2]=max(dp[i-1][j-struct[i].vol]+struct[i].val,dp[i-1][j]),这里就出现问题了,因为物品2的体积为V-1,导致表格(二维数组抽象而来)第二行从0~V-2的值全部是0,这就使得原本可以装入物品1和物品3的背包变成了只装入物品3的背包了
简单的来说,

if(j<struct[i].vol){
			dp[i][j]=dp[i-1][j];

如果没有这段代码,相当于每更新一个物品,我就把背包倒空,从这个物品开始装入
而有了这行代码,表示虽然当前物品我放不进去,但是我这个容量的背包里还有前几次装入的物品,留着看看能不能装入下一个物品,这样就创造了1+3的组合或是其他组合,或者2+3的组合(开头为什么是2?在放入物品2时候,判断背包里只装物品2的价值>背包里只装物品1)

综上所述,i必须从1开始,而j也不能从struct[i].vol出发。

剩下的问题我们可以看图说话,主要是上一节英语课,不能用电脑写,只好画在纸上了,不过纸上能画出表格,想来也是极好的。

在这里插入图片描述

标准代码(最最最基础

memset(dp,0,sizeof(dp));
for(int i=1;i<=N;i++){
	for(int j=0;j<=V;j++){
		if(j<struct[i].vol){
			dp[i][j]=dp[i-1][j];
		}else{
			dp[i][j]=max(dp[i-1][j-struct[i].vol]+struct[i].val,dp[i-1][j]);
		}
	}
}
return dp[i][j];



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值