首页 > 代码库 > 简单背包问题

简单背包问题

今天重温了一下01背包问题,感觉理解有深了一点点

首先我们来说一下这个状态转移方程

dp[i][j] = max( dp[i-1][j],dp[i][j-v[i]]+w[i] )

 其中i是当前背包装的东西个数,j则是当前背包剩余的空间,v[i]是当前第i号物品所占有背包空间的大小,w[i]是第i号物品的价值,看到代码很好理解,状态转移方程的意思就是当前的物品放入或者不放入背包而得到的价值的最优值

看法这里我又开始疑惑了,为什么根据状态转移方程就可以求解出背包的最优解?然后开始思考,当前的最优值是真么来的?是根据上一阶段的所有值里面挑选出来的,好像跟上上一阶段没有关系,然后上一阶段的值则是根据上上阶段的值来的,说到这里,好像有点递归的感觉?然后我仔细查看了一下上一阶段(就是dp[i][])里面的所有值,现在我明白了,那么,来一道题目来解释一下,题目来自大牛的博客(以下大部分内容来自大牛的博客+我自己少量的见解以及感悟)

大牛博客里面的题目我就直接复制过来了,

给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?

对于一种物品,要么装入背包,要么不装。所以对于一种物品的装入状态可以取0和1.我们设物品i的装入状态为xi,xi∈ (0,1),此问题称为0-11背包问题。

数据:物品个数n=5,物品重量w[n]={0,2,2,6,5,4},物品价值V[n]={0,6,3,5,4,6},

然后大牛给了几张图,图里的数据就是根据上面的状态转移方程得来的,我就直接贴图了

技术分享

这张图是第一次dp得到的数据,简单模拟一下dp的方程即可(不明白的话,博客最下面有代码实现,可以运行一下,自己加一下打印数据的代码),

先解释一下涂图上的数据,w右边一列数据是物品的编号,从1到5号,w则是对应物品的质量(体积),图片最右边的v则是对应物品的价值,图的最上方,是当前背包的容量,下面是核心代码

for( int i = 1; i <= N; i++ ){    for( j = v[i]; j <= K; j++ ){        dp[i][j] = max(dp[i-1][j],dp[i-1][j-v[i]]+w[i]);    }}

里面的数据是怎么来的,左下方的四个为什么是0?根据上面的代码,第5个物品的w是4,所以如果背包的体积小于当前的物品的体积,那么,物品是无法放入的,反之则可以放入,对应dp[i][j]的值要加上当前物品的价值,然后继续看第二张图

技术分享

这张图把第二行也填好了,第而行的数据是根据第一行来的,继续,模拟代码,因为第二个物品的体积是5,所以当要是背包的剩余空间小于5,那么就无法放入,所以上面代码里的第二个for循环至少要从v[i]开始,我们继续看0000后面的数据,当背包的容量小于(v[5]+v[4])的时候,我们肯定取最优值为v[0],当背包的容量为9以及以后,那么v[4]就可以被放入,当前的最优值当然就是w[5]+w[4] = 10了.然后我们在来看第三张图

技术分享

很显然,掐面前面都一样,我们直接看后面的数据,当背包的容量为9的时候,当前的3号物品仍然无法放进去,而当背包的容量为10的时候,我们发现值变成11了,因为加入把3号跟5号一起放入的话,总的价值比放4号和5号要高,但是这不操作是怎么来的呢?根据状态转移方程d[3][10] = max(dp[2][10],dp[2][10-6]+5),而dp[2][4] = 6,所以根据这个方程我们选择了放入5号和3号,

我们看到这里就可以很明白了,dp[i][j]就是放了i个物品,剩余空间为j时候的最优值,而我们把每个最优值都保存起来,当下次要计算dp[i+1]时候,dp[i]就派上了用场

语无伦次,本人的拙见,希望大牛可以指正

简单背包问题