背包DP详解

1. 01 01 01背包

题目简介:

n n n个物品和一个容量为 v v v的背包,每个物品的价值为 c [ i ] c[i] c[i],体积为 w [ i ] w[i] w[i],要求选择一些物品放入背包中,使物品总体积不超过 m m m的前提下,物品的总价值最大,求最大总价值。

基本思路:

这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。用子问题定义状态:即 f [ i ] [ j ] f[ i ][ j ] f[i][j]表示前 i i i 件物品恰放入一个容量为 j j j的背包可以获得的最大价值。则其状态转移方程便是:

f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+c[i]);
/*
f[i-1][v]为不取第i件物品,让前i-1件物品来装v这么大的空间
f[i-1][v-w[i]]+c[i]为取第i件物品,让前i-1件物品来装v-w[i]这
么大的空间(因为要给第i件物品腾空间,所以是v-w[i]),然后加上
第i件物品的价值。
这里要注意,j要大于等于w[i]
*/

核心代码如下:

for(int i=1;i<=n;i++) {
   
	for(int j=0;j<=m;j++) {
   
		f[i][j]=f[i-1][j];
		if(f[i-1][j-w[i]]+c[i]>f[i][j])
			f[i][j]=f[i-1][j-w[i]]+c[i];
	}
}

优化:

细细一品,其实我们可以用滚动数组来优化,因为我们可以发现第 i i i个阶段的决策只与第 i − 1 i - 1 i1阶段有关,所以我们第一维只用开 2 2 2
核心代码:

int f[2][1005];
//第二维的大小就是v的范围,我这里是随便编得一个
for(int i=1;i<=n;i++) {
   
	for(int j=0;j<=m;j++) {
   
		f[i&1][j]=f[(i-1)&1][j];
		if(f[(i-1)&1][j-w[i]]+c[i]>f[i&1][j])
			f[i&1][j]=f[(i-1)&1][j-w[i]]+c[i];
	}
}

再细细一品,在每个阶段的开始时,实际上执行了一次从 f [ i − 1 ] [ ] f[ i-1 ][] f[i1][] f [ i ] [ ] f[ i ][] f[i][]的拷贝操作,于是我们就可以将二维改为一维。 f [ j ] f[ j ] f[j]表示背包中放入总体积为 j j j 的物品的总价值。
核心代码:

for(int i=1;i<=n;i++) {
   
	for(int j=m;j>=w[i];j--) {
   
		f[j]=max(f[j],f[j-w[i]]+c[i]);
	}
}

注意,这里我们是用的倒序循环。循环到 j j j时:
f f f数组中 f [ j   m ] f[j~m] f[j m]处于第 i i i个阶段, f [ 0   j −

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值